C 具有相同名称的指针和正则变量

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] )

在《嵌入式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] )
            *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];

如果(*max
int 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
时,它指的是e
int*
参数。@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}