take for example the following C code :
int main(int argc, char *argv[])
{
signed char i;
unsigned char count = 0xFF;
for (i=0; i<count;i++)
{
printf("%x\n", i);
}
return 0;
}
This code runs in an infinite loop, even if I compile it as follows :
# gcc -Wall -Wpedantic -Wconversion -Wsign-compare -Wtype-limits -Wsign-conversion test.c -o test
Does someone know for a compiler flag that should warn about those kind of issues ?
Just to be clear, I'm not asking 'why is get an infinite loop', but to know if there's a way to prevent it using a compiler or static analysis ?
A signed char is a signed value which is typically smaller than, and is guaranteed not to be bigger than, a short . An unsigned char is an unsigned value which is typically smaller than, and is guaranteed not to be bigger than, a short .
In the book "Complete Reference of C" it is mentioned that char is by default unsigned.
Signed char and unsigned char both are used to store single character. The variable stores the ASCII value of the characters. For an example if 'A' is stored, actually it will hold 65. For signed char we need not to write the signed keyword.
The XDR standard defines signed integers as integer. A signed integer is a 32-bit datum that encodes an integer in the range [-2147483648 to 2147483647]. An unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0 to 4294967295].
The flag -Wconversion won't catch the error, because both operands in the comparison: i<count
, get promoted to int using integer promotions.
There is no flag in gcc that would catch this.
That aside, the behavior of your code is undefined, because variable i overflows, when it has the value 0x7F
and is incremented: i++
.
If you want to iterate up to some value, make sure the type you're using can represent that value.
i
is a signed char
, incrementing it beyond SCHAR_MAX
has an implementation defined effect. The computation i + 1
is performed after promotion of i
to int
and it does not overflow (unless sizeof(int) == 1
and SCHAR_MAX == INT_MAX
). Yet this value is beyond the range of i
and since i
has a signed type, either the result is implementation-defined or an implementation-defined signal is raised. (C11 6.3.1.3p3 Signed and unsigned integers).
By definition, the compiler is the implementation, so the behavior is defined for each specific system and on x86 architectures where storing the value results in masking the low-order bits, gcc
should be aware that the loop test is definitely constant, making it an infinite loop.
Note that clang
does not detect the constant test either, but clang 3.9.0
will if count
is declared as const
, and it does issue a warning if i < count
is replaced with i < 0xff
, unlike gcc
.
Neither compiler complains about the signed / unsigned comparison issue because both operands are actually promoted to int
before the comparison.
You found a meaningful issue here, especially significant because some coding conventions insist on using the smallest possible type for all variables, resulting in such oddities as int8_t
or uint8_t
loop index variables. Such choices are indeed error-prone and I have not yet found a way to get the compiler to warn the programmer about silly errors such as the one you posted.
Since i
is a signed char
, its value ranges from -128 to 127
typically. Whereas count
being an unsigned char
is assigned the value 255 (0xFF)
.
Inside the loop, when i
value gets to 127
and is incremented again, it never reaches 128
and gets to -128
and then gets again to 127
and then again rolls over to -128
, and so on. The value of i
will be forever less than the value of count
inside the loop and so the loop can never terminate!
This is happening because of the overflow of the data type and care must be taken to critically examine the expressions where automatic type coercions may take place as they will not issue any warning.
EDIT: From the GCC documentation,
-Wconversion: Warn for implicit conversions that may alter a value.
Here, we are getting inconsistency due to comparison and not assignment.
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