Loop starting at -1 doesn't print anything [duplicate]
This program is supposed to print out the elements of array
, but when it is run, no output is shown.
#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;
}
Why doesn't this program show any output?
Solution 1:
sizeof
returns an unsigned integer, so TOTAL_ELEMENTS
is also unsigned.
d
is signed. Initially, d
is -1
. However, when doing the comparison, d
is implicitly typecast to unsigned, so it is no longer -1
when being compared to TOTAL_ELEMENTS
, it is actually UINT_MAX
(which is 4294967295
on my machine, but might differ for others).
Also,
If you want to fix this, typecast TOTAL_ELEMENTS
to int
:
for(d = -1; d <= (int)(TOTAL_ELEMENTS - 2); d++)
This will print:
23
34
12
17
204
99
16
As you'd expect. You may also want to look at Comparison operation on unsigned and signed integers for more information on the topic of signed-unsigned comparisons.
It is worth noting that turning on compiler warnings would've helped you figure out what was going on (as observed by hyde in his comment):
$ gcc -Wall -Wextra test.c
test.c:7:17: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
for(d = 0; d < TOTAL_ELEMENTS; d++)
~ ^ ~~~~~~~~~~~~~~
1 warning generated.
Alternatively, why not start d
at 0
and run to TOTAL_ELEMENTS - 1
instead? You can even drop the typecast, that is necessary only for the corner case of d = -1
.
for(d = 0; d < TOTAL_ELEMENTS; d++)
printf("%d\n", array[d]);
As a footnote, here are the relevant C99 Standard excerpts:
-
6.3.1.8p2 defines the conversion from signed to unsigned type.
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.
-
6.3.1.3p2 defines how the conversion is done: By adding
UINT_MAX + 1
to the signed representation.If the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
So
-1
=>-1 + (UINT_MAX + 1)
=UINT_MAX
, for this scenario.
Solution 2:
My gcc outputs this warning:
warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
for(d = 0; d < TOTAL_ELEMENTS; d++)
which means that (TOTAL_ELEMENTS-2)
is unsigned int
while d
is signed int
. This makes the expression always false
for the initial value of d
, since (unsigned int)(-1) > (TOTAL_ELEMENTS-2)
.
Solution 3:
Binary operations between different integral types are performed within a "common" type defined by so called usual arithmetic conversions. So int d is of singed type initialized with value -1. Which when convert into unsigned int it will return maximum of unsigned int which is much much greater than the value returned by TOTAL_ELEMENTS.