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?
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]);
}
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]))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With