What is wrong with following C code? [duplicate]

只谈情不闲聊 提交于 2019-12-12 03:15:10

问题


Possible Duplicate:
Confused about C macro expansion and integer arithmetic
A riddle (in C)

The expected output of the following C program is to print the elements in the array. But when actually run, it doesn't do so.

#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;
  }

回答1:


Because sizeof gives you an unsigned value, which you probably would have noticed had you turned up the warning level, such as using -Wall -Wextra with gcc (a):

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

If you force it to signed, it works fine:

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

What happens in detail can be gleaned from the ISO standard. In comparisons between different types, promotions are performed to make the types compatible. The compatible type chosen depends on several factors such as sign compatibility, precision and rank but, in this case, it was deemed that the unsigned type size_t was the compatible type so d was upgraded to that type.

Unfortunately, casting -1 to an unsigned type (at least for two's complement which is almost certainly what you're using) results in a rather large positive number.

One that's certainly larger the the 5 you get from (TOTAL_ELEMENTS-2). In other words, your for statement effectively becomes:

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

(a) This requirement to use extra remains a point of contention between the gcc developers and myself. They're obviously using some new definition of the word "all" of which I was previously unaware (with apologies to Douglas Adams).




回答2:


TOTAL_ELEMENTS is of type size_t, subtracting 2 is done at compile time and so it is 5UL (emphasis on the unsigned suffix). The comparison with the signed integer d is then always false. Try

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

FTW, the intel compiler warns about exactly this when you try and compile the code.




回答3:


To clarify what went wrong: sizeof() translates to a result type of size_t, which is nothing but an unsigned integer, larger than or equal to unsigned int.

So the result of (sizeof(array) / sizeof(array[0])) is a result in two operands of size_t type. The division is performed on these operands:size_t / size_t. Both operands are of the same type so it works fine. The result of the division is of type size_t, which is the type that TOTAL_ELEMENTS results in.

The expression (TOTAL_ELEMENTS-2) therefore have the types size_t - int, since the integer literal 2 is of type int.

Here we have two different types. What happens then is something called balancing (formally "the usual arithmetic conversions"), which happens when the compiler spots two different types. The balancing rules state that if one operand is signed and the other unsigned, then the signed one is silently, implicitly converted to an unsigned type.

This is what happens in this code. size_t - int is converted to size_t - size_t, then the subtraction is executed, the result is size_t. Then int <= size_t is converted to size_t <= size_t. The variable d turns unsigned, and if it had a negative value, the code goes haywire.



来源:https://stackoverflow.com/questions/9902140/what-is-wrong-with-following-c-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!