Loop starting at -1 doesn't print anything
CLoopsIntegerSizeofNegative NumberC Problem Overview
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?
C Solutions
Solution 1 - C
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 https://stackoverflow.com/questions/2084949/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 - C
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 - C
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.