可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has an answer here:
-
A riddle (in C)
4 answers
In the code shown below, nothing gets printed, which means the condition in the for
loop fails. What could be the reason?
I'm wondering because when I print TOTAL_ELEMENTS
separately, it gives 5
, so naturally this must be 5-2=3 => -1<=3
, so it should print something.
#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;
}
Can someone explain this code?
回答1:
This is a result of the "usual arithmetic conversions".
From section 6.3.1.8 of the C standard:
If both operands have the same type, then no further conversion is
needed.
Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser
integer conversion rank is converted to the type of the operand
with greater rank.
Otherwise, if the operand that has unsigned integer type has
rank greater or equal to the rank of the type of the other
operand, then the operand with signed integer type is
converted to the type of the operand with unsigned integer
type.
Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned
integer type, then the operand with unsigned integer type is
converted to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned
integer type corresponding to the type of the operand with signed
integer type.
The sizeof
operator returns a size_t
, which is an unsigned value. So (sizeof(array) / sizeof(array[0])) - 2
is also unsigned.
Because you are comparing a signed and an unsigned value, the signed value is converted to unsigned. Converting -1 to unsigned results in the largest unsigned value, which results in the comparison being false.
If you cast the right hand side to int
, it will work as expected.
for(d=-1;d <= (int)(TOTAL_ELEMENTS-2);d++)
Output:
23
34
12
17
204
99
16
Or you could avoid the issue by normalizing how you index the array:
for (d = 0; d < TOTAL_ELEMENTS; d++) {
printf("%d\n", array[d]);
}
回答2:
When I try to print TOTAL_ELEMENTS - 2
like this:
printf("total %d\n", TOTAL_ELEMENTS - 2);
I got an warning (using gcc 4.8) saying:
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);
^
The warning means that TOTAL_ELEMENTS - 2
is long unsigned
. Now when you compare a signed int
with unsigned int
, that signed int is treated as unsigned. So in d <= (TOTAL_ELEMENTS-2)
, d
becomes a very high valued positive number (assuming 2's complement number system is used).
You can cast the result to int
to fix the issue.
d <= (int)(TOTAL_ELEMENTS-2)
Or if you are using the macro in many places then you can change that like this:
#define TOTAL_ELEMENTS (int)(sizeof(array) / sizeof(array[0]))
回答3:
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
This evaluates to an unsigned
type. In your loop, however, d
is a signed
value. In an expression where a signed and unsigned value participate, the signed value is converted to an unsigned. But d
is -1, which cannot fit in an unsigned, so it "wraps around" to the highest unsigned value on the machine (on 2's complement).
回答4:
As already explained by other answers, the cause are usual arithmetic conversions, the type size_t obtained using sizeof
causes int to get converted to unsigned type corresponding to type size_t.
I would like to add that the behavior is implementation defined1. The loop can be taken or not. This depends on the definition of the type size_t.
C Standard permits that type size_t has a lower rank than type int. In that case integer promotions promote the type size_t to type int. At that point both sides have the same type int, so the conversions stop. The comparison d <= (TOTAL_ELEMENTS - 2)
then yields true, and the loop is taken.
1 The program is therefore not strictly conforming as the output relies on implementation-defined behavior.
回答5:
You know #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])) returns an unsigned number, and -1 may become the largest number, because it converts to a unsigned number.
And you can test the expression "printf("%d\n", -1 < TOTAL_ELEMENTS);"; it prints 0. So we can solve by adding (int) before (TOTAL_ELEMENTS - 2) or alter the loop:
for (int d = 0; d < TOTAL_ELEMENTS; d++) {
printf("%d\n", array[d]); }
And I don't think making the d
variable dependent is a good way, because d
is a variable in for
loop.