以下C程序的预期输出是打印数组元素。但实际运行时,它不会这样做。
#include<stdio.h>
#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;
}
是什么原因?
答案 0 :(得分:6)
TOTAL_ELEMENTS
未签名。 -1,当转换为unsigned时,是一个非常大的数字,不小于6.因此,你的循环永远不会运行。
答案 1 :(得分:5)
进行比较d <= (TOTAL_ELEMENTS-2)
时,会执行类型转换。 d
的类型为signed int
,而(TOTAL_ELEMENTS-2)
的类型为size_t
,这是一种无符号类型。 C的规则说当一个运算符有一个signed和一个unsigned参数,并且unsigned参数的大小大于或等于signed参数时,signed参数将被转换为unsigned。
也就是说,比较最终为:
(size_t) d <= (TOTAL_ELEMENTS-2)
由于size_t
是无符号的,(size_t) -1
是一个非常非常大的数字,不再是-1。对于32位size_t
,它将是2 32 - 1 = 4,294,967,295。
要解决此问题,您可以将右侧明确地转换为signed int:
d <= (int) (TOTAL_ELEMENTS-2)
或者,更好的是,只需摆脱奇怪的负面索引等。
为了将来参考,请启用所有编译器警告。例如,如果您打开-Wall -Wextra
:
$ gcc -o arrayprint -Wall -Wextra -ansi arrayprint.c
arrayprint.c: In function ‘main’:
arrayprint.c:11: warning: comparison between signed and unsigned
答案 2 :(得分:3)
起初,我不知道。但是当我使用GCC编译它时,显然很明显:
$ gcc -Wall -Wextra -Os a.c
a.c: In function `main':
a.c:11: warning: comparison between signed and unsigned
所以你有如下比较:
(int) -1 <= (size_t) 5
由于其中一个类型是签名的而另一个是无符号的,因此首先需要将它们转换为通用类型。在这种情况下,它是size_t
。这样做:
(size_t) -1 <= (size_t) 5
现在-1
无法以无符号类型表示。因此,添加了2 ^ 32(或多个位size_t
),这使得它成为4294967295.所以比较真的是:
4294967295 <= 5
那就是false
,因此循环体永远不会被执行。
答案 3 :(得分:1)
原因是循环永远不会执行。这是因为TOTAL_ELEMENTS
返回size_t,一个无符号类型。
您可以通过将(TOTAL_ELEMENTS-2)
强制转换为int来解决此问题。
答案 4 :(得分:0)
您需要执行以下操作:
for(d=0;d < TOTAL_ELEMENTS;d++)
printf("%d\n",array[d]);
因为sizeof(...)
产生无符号值。
答案 5 :(得分:0)
只需更改
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
使用
#define TOTAL_ELEMENTS (int)(sizeof(array)/sizeof(array[0]))-2