为什么'for'循环条件失败?

Ari*_*n.K 12 c type-conversion implicit-conversion c-preprocessor

在下面显示的代码中,没有任何内容被打印,这意味着for循环中的条件失败.可能是什么原因?

我想知道,因为当我TOTAL_ELEMENTS单独打印时,它给出了5,所以它必须是5-2=3 => -1<=3,所以它应该打印一些东西.

#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))

int array[] = { 23, 34, 12, 17, 204, 99, 16 };
int main()
{
    int d;

    for (d = -1; d <= (TOTAL_ELEMENTS - 2); d++) {
        printf("%d\n", array[d + 1]);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

有人可以解释这段代码吗?

dbu*_*ush 33

这是"通常的算术转换"的结果.

C标准的 6.3.1.8节:

如果两个操作数具有相同的类型,则不需要进一步转换.

否则,如果两个操作数都具有有符号整数类型或两者都具有无符号整数类型,则具有较小整数转换等级类型的操作数将转换为具有更高等级的操作数的类型.

否则, 如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型.

否则,如果带有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数将转换为带有符号整数类型的操作数的类型.

否则,两个操作数都转换为无符号整数类型,对应于带有符号整数类型的操作数的类型.

sizeof操作者返回一个size_t,这是一个无符号的值.所以(sizeof(array) / sizeof(array[0])) - 2也是未签名的.

由于您要比较有符号值和无符号值,因此有符号值将转换为无符号值.将-1转换为无符号会导致最大的无符号值,从而导致比较为假.

如果您将右侧投射到int,它将按预期工作.

for(d=-1;d <= (int)(TOTAL_ELEMENTS-2);d++)
Run Code Online (Sandbox Code Playgroud)

输出:

23
34
12
17
204
99
16
Run Code Online (Sandbox Code Playgroud)

或者您可以通过规范化索引数组的方式来避免此问题:

for (d = 0; d < TOTAL_ELEMENTS; d++) {
    printf("%d\n", array[d]);
}
Run Code Online (Sandbox Code Playgroud)


tas*_*oor 9

当我尝试这样打印时TOTAL_ELEMENTS - 2:

printf("total %d\n", TOTAL_ELEMENTS - 2);
Run Code Online (Sandbox Code Playgroud)

我收到警告(使用gcc 4.8)说:

test.c:8:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
  printf("total %d\n", TOTAL_ELEMENTS - 2);
  ^
Run Code Online (Sandbox Code Playgroud)

该警告意味着TOTAL_ELEMENTS - 2long unsigned.现在,当你比较一个signed intwith时unsigned int,那个signed int被视为unsigned.因此d <= (TOTAL_ELEMENTS-2),d成为一个非常高的正数(假设使用2的补数系统).

您可以将结果转换int为修复问题.

d <= (int)(TOTAL_ELEMENTS-2)

或者,如果您在许多地方使用宏,那么您可以像这样更改:

#define TOTAL_ELEMENTS (int)(sizeof(array) / sizeof(array[0]))
Run Code Online (Sandbox Code Playgroud)


Edw*_*rak 5

#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
Run Code Online (Sandbox Code Playgroud)

这将评估为一种unsigned类型.但是,在循环中,它d是一个signed值.在有符号和无符号值参与的表达式中,有符号值将转换为无符号值.但是d-1是-1,它不能适合无符号,因此它"包裹"到机器上的最高无符号值(在2的补码上).