循环从-1开始不打印任何东西
这个程序应该打印出array
的元素,但是当它运行时,没有输出显示。
#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; }
为什么这个程序不显示任何输出?
sizeof
返回一个无符号整数,所以TOTAL_ELEMENTS
也是无符号的。
d
签名。 最初, d
是-1
。 但是,比较的时候, d
是隐含的无符号的types转换,所以当与TOTAL_ELEMENTS
比较时,它不再是-1
,它实际上是UINT_MAX
(在我的机器上是4294967295
,但是对于其他的可能是不同的)。
也,
如果你想解决这个问题, TOTAL_ELEMENTS
types转换为int
:
for(d = -1; d <= (int)(TOTAL_ELEMENTS - 2); d++)
这将打印:
23 34 12 17 204 99 16
正如你所期望的那样。 您也可以查看有关未签名和有符号整数的比较操作,以获取有关无符号签名比较主题的更多信息。
值得注意的是,打开编译器警告可以帮助你弄清楚发生了什么事情(正如海德在他的评论中所观察到的那样):
$ gcc -Wall -Wextra test.c test.c:7:17: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare] for(d = 0; d < TOTAL_ELEMENTS; d++) ~ ^ ~~~~~~~~~~~~~~ 1 warning generated.
或者,为什么不从0
开始d
并运行到TOTAL_ELEMENTS - 1
呢? 你甚至可以删除这个types转换,只有在d = -1
情况下才需要。
for(d = 0; d < TOTAL_ELEMENTS; d++) printf("%d\n", array[d]);
作为脚注,以下是相关的C99标准摘录:
-
6.3.1.8p2定义了从签名到无符号types的转换。
如果具有无符号整数types的操作数具有大于或等于另一操作数types的等级,则具有有符号整数types的操作数被转换为具有无符号整数types的操作数的types。
-
6.3.1.3p2定义了如何完成转换:通过将
UINT_MAX + 1
添加到有符号表示中。如果新types是无符号的,则通过重复join或减去新types中可以表示的最大值之一来转换该值,直到该值在新types的范围内。
所以对于这个场景,
-1
=>-1 + (UINT_MAX + 1)
=UINT_MAX
。
我的gcc输出这个警告:
warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare] for(d = 0; d < TOTAL_ELEMENTS; d++)
这意味着(TOTAL_ELEMENTS-2)
是unsigned int
而d
是有signed int
。 因为(unsigned int)(-1) > (TOTAL_ELEMENTS-2)
,所以这个expression式对于d
的初始值总是为false
。
不同整数types之间的二进制操作在由所谓的常规算术转换定义的“公共”types内执行。 所以int d是用值-1初始化的单types。 当转换为unsigned int时,它将返回最大的unsigned int,这比TOTAL_ELEMENTS返回的值大得多。