以下C代码有什么问题?

可能重复:
对C宏扩展和整数运算感到困惑
一个谜语(在C中)

以下C程序的预期输出是打印数组中的元素。 但是当实际运行时,它不会这样做。

#include #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为您提供了一个无符号值,如果您调高警告级别,可能会注意到这一点,例如使用-Wall -Wextragcc (a)

 xyzzy.c: In function 'main': xyzzy.c:8: warning: comparison between signed and unsigned 

如果强制它签名,它可以正常工作:

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

可以从ISO标准中收集详细信息。 在不同类型之间的比较中,执行促销以使类型兼容。 选择的兼容类型取决于几个因素,例如符号兼容性,精度和等级,但在这种情况下,认为无符号类型size_t是兼容类型,因此d已升级到该类型。

不幸的是,将-1转换为无符号类型(至少对于两个补码,这几乎肯定是你正在使用的)会导致相当大的正数。

一个肯定比你得到的5 (TOTAL_ELEMENTS-2)更大。 换句话说,您的for语句实际上变为:

 for (d = some big honking number way greater than five; d <= 5; d++ ) { // fat chance of getting in here !! } 

(a)这种使用extra要求仍然是gcc开发者和我之间争论的焦点。 他们显然使用了我之前没有意识到的“所有”这个词的一些定义(道格拉斯亚当斯道歉)。

TOTAL_ELEMENTS的类型为size_t ,减去2是在编译时完成的,因此它是5UL (强调无符号后缀)。 然后,与有符号整数d的比较总是为假。 尝试

 for(d=-1;d <= (ssize_t)(TOTAL_ELEMENTS-2);d++) 

FTW,当您尝试编译代码时,intel编译器会对此发出警告。

为了弄清楚出现了什么问题:sizeof()转换为size_t的结果类型,它只是一个无符号整数,大于或等于unsigned int

因此(sizeof(array) / sizeof(array[0]))的结果是两个size_t类型的操作数的结果。 对这些操作数执行除法: size_t / size_t 。 两个操作数都是相同的类型,所以它工作正常。 除法的结果是size_t类型,这是TOTAL_ELEMENTS导致的类型。

因此,表达式(TOTAL_ELEMENTS-2)具有size_t - int类型,因为整数文字2的类型为int。

这里我们有两种不同的类型。 然后发生的事情是称为平衡 (正式的“通常的算术转换”),当编译器发现两种不同的类型时会发生这种情况。 平衡规则规定如果一个操作数是有符号的而另一个是无符号的,那么有符号的操作数将被静默,隐式转换为无符号类型。

这是此代码中发生的情况。 size_t - int转换为size_t - size_t ,然后执行减法,结果为size_t 。 然后int <= size_t转换为size_t <= size_t 。 变量d变为无符号,如果它具有负值,则代码变得混乱。