C 具有相同名称的指针和正则变量
在《嵌入式C编程》一书的“内存和指针”一章中,Mark Siegesmund给出了以下示例:C 具有相同名称的指针和正则变量,c,pointers,embedded,C,Pointers,Embedded,在《嵌入式C编程》一书的“内存和指针”一章中,Mark Siegesmund给出了以下示例: void Find_Min_Max( int list[], int count, int * min, int * max){ for( int i=0, min=255, max=0; i<count; i++){ if( *min>list[i]) *min=list[i]; if( *max<list[i] )
void Find_Min_Max( int list[], int count, int * min, int * max){
for( int i=0, min=255, max=0; i<count; i++){
if( *min>list[i])
*min=list[i];
if( *max<list[i] )
*max=list[i];
}
}
// call like this: Find_Min_Max( table, sizeof(table), &lowest, &highest);
void Find_Min_Max(int list[],int count,int*Min,int*Max){
对于(int i=0,min=255,max=0;ilist[i])
*min=列表[i];
如果(*max这是代码中的错误。可能应该是:
for( int i=0, *min=255, *max=0; i<count; i++){
if( *min>list[i])
*min=list[i];
if( *max<list[i] )
*max=list[i];
}
for(int i=0,*min=255,*max=0;ilist[i])
*min=列表[i];
如果(*maxint i=0,min=255,max=0
和int i=0,*min=255,*max=0
都定义了三个新变量,它们已初始化,但在循环体中使用不正确
应在循环之前初始化限制:
*min=255;
*max=0;
for(int i=0; i<count; i++)
请注意,如果存在小于0
或大于255
的值,则返回的最小值和最大值将不正确。这似乎是本书中的错误-它确实在循环中声明了新变量。(提示:在出版编程书籍之前,至少先编译代码…)
但即使修复了那个令人尴尬的错误,代码还是很幼稚。这里还有更多错误:
- 始终
const
限定未修改的数组参数
- 在嵌入式系统中始终使用
stdint.h
- 切勿使用像
255
这样的幻数。在这种情况下,请改用UINT8\u MAX
以上为行业标准共识。(MISRA-C等也要求)
另外,对于数组的大小使用size\u t
而不是int
是最正确的做法,但这更像是一个风格问题
此外,更好的算法是让指针指向数组中找到的最小值和最大值,这意味着我们不仅可以得到值,还可以得到它们在数据容器中的位置。找到位置是一个非常常见的用例。执行速度大致相同,但我们可以获得更多信息
因此,如果我们试图将其改写为一些值得一读的代码,它更像是:
void find_min_max (const uint8_t* data, size_t size, const uint8_t** min, const uint8_t** max);
更难阅读和使用指向指针的指针,但功能更强大
(通常我们会使用restrict
对同一类型的指针进行微优化,但在这种情况下,所有指针都可能指向同一个对象,因此这是不可能的。)
完整示例:
#include <stddef.h>
#include <stdint.h>
void find_min_max (const uint8_t* data, size_t size, const uint8_t** min, const uint8_t** max)
{
*min = data;
*max = data;
for(size_t i=0; i<size; i++)
{
if(**min > data[i])
{
*min = &data[i];
}
if(**max < data[i])
{
*max = &data[i];
}
}
}
正在为ARM gcc-O3分解此搜索算法:
find_min_max:
cmp r1, #0
str r0, [r2]
str r0, [r3]
bxeq lr
push {r4, lr}
add r1, r0, r1
.L5:
mov lr, r0
ldr ip, [r2]
ldrb r4, [ip] @ zero_extendqisi2
ldrb ip, [r0], #1 @ zero_extendqisi2
cmp r4, ip
strhi lr, [r2]
ldr r4, [r3]
ldrbhi ip, [r0, #-1] @ zero_extendqisi2
ldrb r4, [r4] @ zero_extendqisi2
cmp r4, ip
strcc lr, [r3]
cmp r1, r0
bne .L5
pop {r4, pc}
仍然不是最有效的代码,分支非常密集。我认为如果目标是库质量代码,则有足够的空间进行进一步优化。但这也是一种专门的算法,可以同时查找最小值和最大值,以及它们各自的索引
对于小数据集,可能更明智的做法是先对数据进行排序,然后从排序后的最小索引和最大索引中提取最小和最大索引。如果您计划在代码中的其他地方搜索数据,那么一定要先对数据进行排序,以便使用二进制搜索。这不是该代码中唯一的错误::
而不是;
,将min
和max
参数隐藏在循环中,尝试取消引用int
变量,假设列表可以包含不超过255个项目,但不包括空列表,…这是:而不是;我的打字错误(现已更正).for(int i=0,max=1,min=2;i@dietervansteenwegegnon4dd:for
loop init语句定义了3个新的int
变量(i
,min
和max
)。后两个变量与周围范围中的变量同名,因此它们隐藏了for
循环范围内的变量。即,当在for
循环内使用min
时,它指的是init语句中定义的int
——当在for
循环外使用min
时,它指的是eint*
参数。@Sanderedycker这很有意义,消除了我的一些疑虑。我不能将它标记为答案,因为它在注释中……这定义了一个新变量(int*min=255
)然后取消引用它,导致访问冲突。@vll所以更好的选择是在for循环之前初始化*min和*max?注意:避免这种问题的安全方法是将min
和max
初始化为第一个值,即list[0]
#include <stddef.h>
#include <stdint.h>
void find_min_max (const uint8_t* data, size_t size, const uint8_t** min, const uint8_t** max)
{
*min = data;
*max = data;
for(size_t i=0; i<size; i++)
{
if(**min > data[i])
{
*min = &data[i];
}
if(**max < data[i])
{
*max = &data[i];
}
}
}
#include <stdio.h>
#include <inttypes.h>
int main (void)
{
const uint8_t data[] = { 1, 2, 3, 4, 5, 4, 3, 2, 1, 0};
const uint8_t* min;
const uint8_t* max;
find_min_max(data, sizeof data, &min, &max);
printf("Min: %"PRIu8 ", index: %d\n", *min, (int)(min-data));
printf("Max: %"PRIu8 ", index: %d\n", *max, (int)(max-data));
return 0;
}
find_min_max:
cmp r1, #0
str r0, [r2]
str r0, [r3]
bxeq lr
push {r4, lr}
add r1, r0, r1
.L5:
mov lr, r0
ldr ip, [r2]
ldrb r4, [ip] @ zero_extendqisi2
ldrb ip, [r0], #1 @ zero_extendqisi2
cmp r4, ip
strhi lr, [r2]
ldr r4, [r3]
ldrbhi ip, [r0, #-1] @ zero_extendqisi2
ldrb r4, [r4] @ zero_extendqisi2
cmp r4, ip
strcc lr, [r3]
cmp r1, r0
bne .L5
pop {r4, pc}