为啥'for'循环条件失败? [复制]
Posted
技术标签:
【中文标题】为啥\'for\'循环条件失败? [复制]【英文标题】:Why does the 'for' loop condition fail? [duplicate]为什么'for'循环条件失败? [复制] 【发布时间】:2016-12-26 18:29:56 【问题描述】:在下面显示的代码中,没有打印任何内容,这意味着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;
谁能解释一下这段代码?
【问题讨论】:
见:***.com/questions/31361713/… “因为当我单独打印 TOTAL_ELEMENTS 时,结果为 5” - 不,不是。你有什么理由让它这么复杂? 我不知道您使用的是哪个编译器,但 GCC 会给出正确的提示:“警告:有符号整数和无符号整数之间的比较”。当然,如果您已打开所有警告。谁给了这 8 个(用词:8 个!)赞成票? @deamentiaemundi 只有-Wextra
才会发出警告。不是每个人都使用它,但每个人都应该使用它。
什么是for循环从-1开始,然后数组索引加1的原因?
【参考方案1】:
正如其他答案已经解释的那样,原因是通常的算术转换,使用sizeof
获得的类型 size_t 导致 int 转换为对应于类型 size_t 的无符号类型。
我想补充一点,行为是实现定义的1。可以采取或不采取循环。这取决于 size_t 类型的定义。
C 标准允许 size_t 类型的等级低于 int 类型。在这种情况下,整数提升将 size_t 类型提升为 int 类型。此时双方都具有相同的 int 类型,因此转换停止。比较 d <= (TOTAL_ELEMENTS - 2)
则结果为真,并执行循环。
1 因此,该程序并不严格遵守,因为输出依赖于实现定义的行为。
【讨论】:
【参考方案2】:你知道#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])) 返回一个无符号数,-1 可能成为最大数,因为它转换为一个无符号数。
你可以测试表达式 "printf("%d\n", -1
for (int d = 0; d < TOTAL_ELEMENTS; d++)
printf("%d\n", array[d]);
而且我不认为使d
变量依赖是一个好方法,因为d
是for
循环中的一个变量。
【讨论】:
【参考方案3】:这是“通常的算术转换”的结果。
来自C standard 的第 6.3.1.8 节:
如果两个操作数的类型相同,则不再进行转换 需要。
否则,如果两个操作数都具有有符号整数类型或都具有 无符号整数类型,具有较小类型的操作数 整数转换等级转换为操作数的类型 排名更高。
否则,如果具有无符号整数类型的操作数具有 等级大于或等于其他类型的等级 操作数,则带符号整数类型的操作数为 转换为无符号整数的操作数类型 输入。
否则,如果带符号整数类型的操作数的类型可以 用无符号表示操作数类型的所有值 整数类型,则无符号整数类型的操作数为 转换为带符号整数类型的操作数的类型。
否则,两个操作数都转换为无符号数 与带符号的操作数类型对应的整数类型 整数类型。
sizeof
运算符返回一个size_t
,它是一个无符号值。所以(sizeof(array) / sizeof(array[0])) - 2
也是无符号的。
因为您正在比较有符号和无符号值,所以将有符号值转换为无符号值。将 -1 转换为无符号会产生最大的无符号值,这会导致比较结果为假。
如果您将右侧转换为int
,它将按预期工作。
for(d=-1;d <= (int)(TOTAL_ELEMENTS-2);d++)
输出:
23
34
12
17
204
99
16
或者您可以通过规范化数组的索引方式来避免该问题:
for (d = 0; d < TOTAL_ELEMENTS; d++)
printf("%d\n", array[d]);
【讨论】:
【参考方案4】:#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
计算结果为unsigned
类型。但是,在您的循环中,d
是一个 signed
值。在有符号和无符号值参与的表达式中,有符号值被转换为无符号值。但是d
是-1,它不能放入无符号数中,因此它“环绕”到机器上的最高无符号值(在 2 的补码上)。
【讨论】:
【参考方案5】:当我尝试像这样打印TOTAL_ELEMENTS - 2
时:
printf("total %d\n", TOTAL_ELEMENTS - 2);
我收到一条警告(使用 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);
^
警告意味着TOTAL_ELEMENTS - 2
是long unsigned
。现在,当您将signed int
与unsigned int
进行比较时,有符号的int 被视为无符号的。所以在d <= (TOTAL_ELEMENTS-2)
中,d
变成了一个非常高值的正数(假设使用了 2 的补数系统)。
您可以将结果转换为 int
以解决问题。
d <= (int)(TOTAL_ELEMENTS-2)
或者,如果您在很多地方都使用宏,那么您可以这样更改:
#define TOTAL_ELEMENTS (int)(sizeof(array) / sizeof(array[0]))
【讨论】:
以上是关于为啥'for'循环条件失败? [复制]的主要内容,如果未能解决你的问题,请参考以下文章