I have been advised to use the following options with GCC, as it helps to avoid a lot of common errors. It turns on a bunch of warnings and -Werror
turns them into errors.
gcc -pedantic -W -Wall -Wextra -Wshadow -Wstrict-overflow=5 -Wwrite-strings -std=c99 -Werror
Given the following test code:
#include <stdio.h>
int main(void)
{
int arr[8]={0,10,20,30,40,50,60,70};
int x;
printf("sizeof(arr): %d\n", sizeof(arr));
printf("sizeof(int): %d\n", sizeof(int));
for(x = 0; x < sizeof(arr)/sizeof(int); x++)
{
printf("%d\n",arr[x]);
}
return 0;
}
I get this:
test.c:11: error: comparison between signed and unsigned
I know that one way I can fix this is turning off the warnings, but they haven't made me use these settings to turn them off in the end.
Another way is to cast the stuff, but I have been told that casting is deprecated.
Also, I could make x into an unsigned int
:
unsigned x;
But it doesn't solve the general problem when I have to compare signed values with unsigned values using these compiler options. Is there an cleaner way instead of casting?
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 signed integer is represented in twos complement notation.
Type in -Wno-sign-compare The warning -Wsign-compare can be negated by adding "-Wno" as a prefix. In fact warnings can be ignored by adding -Wno- to the warning code.
Sure, comparisons between signed and unsigned would be slower, but their result would be more correct in some sense. @Nawaz Your bottom line conclusion is incorrect, unfortunately: if the signed type can contain the unsigned type, the unsigned will be converted to the signed type and not the opposite.
The hardware is designed to compare signed to signed and unsigned to unsigned. If you want the arithmetic result, convert the unsigned value to a larger signed type first. Otherwise the compiler wil assume that the comparison is really between unsigned values. And -1 is represented as 1111..
This really depends on the data type. It is possible to avoid this by implicitly casting the values to a type which contains a superset of all the values available in the signed and unsigned type. For instance you could use a 64 bit signed value to compare an unsigned 32 bit and a signed 32 bit value.
However this is a corner case and you need to do operations like verify the size of your types. Your best solution is to use the same type for both operands.
If you must cast, do consider that you could be causing an overflow and consider if that is important to your application or not.
Replace
int x;
/* ... */
for(x=0;x<sizeof(arr) / sizeof(int);x++)
by
for(size_t x=0;x<sizeof(arr) / sizeof(int);x++)
But it doesn't solve the general problem when I have to compare signed values with unsigned values using these compiler options. Is there an cleaner way insted of casting?
In such cases, try to figure out if the signed number can ever have a value which will cause overflow. If not, you can ignore the warning. Otherwise a cast to the unsigned type (if this is the same size or bigger than the signed component) is good enough.
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