以下C代码有什么问题?

时间:2012-03-28 06:21:56

标签: c arrays c-preprocessor

  

可能重复:
  Confused about C macro expansion and integer arithmetic
  A riddle (in C)

以下 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;
  }

3 个答案:

答案 0 :(得分:6)

因为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开发人员与我之间争论的焦点。他们显然正在使用我之前未发现的“所有”一词的 new 定义(道格拉斯亚当斯道歉)。

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

澄清出现了什么问题: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。

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

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