How do you explain that line 7 gets a warning, but not line 5 or line 6?
int main()
{
unsigned char a = 0xFF;
unsigned char b = 0xFF;
a = a | b; // 5: (no warning)
a = (unsigned char)(b & 0xF); // 6: (no warning)
a = a | (unsigned char)(b & 0xF); // 7: (warning)
return 0;
}
GCC 4.6.2 output when compiled on 32-bit architecture (Windows PC):
gcc -c main.c --std=c89 -Wall -Wextra -Wconversion -pedantic
main.c: In function 'main':
main.c:7:11: warning: conversion to 'unsigned char' from 'int' may alter its value [-Wconversion]
If this helps you understand my question, here is how I see this (probably incorrect!):
I suppose that on a 32-bit machine operations are done on 32-bit numbers. Since unsigned char
fits into 32-bit int
, the operation result is 32-bit int
. But since GCC doesn't give warnings on lines 5 and 6, I guess there is something else going on:
line 5: GCC figures that (uchar) OR (uchar) is never bigger than MAX(uchar), so no warning.
line 6: GCC figures that (uchar) AND 0xF is never bigger than MAX(uchar), so no warning. Explicit cast is not even necessary.
line 7: Based on assumptions above: AND should not give warning (since line 6), OR should not give warning either (since line 5).
I guess my logic is faulty somewhere there. Help me understand the logic of the compiler.
Compilers are built by people and they don't have infinite time to figure out all arithmetic possibilities to decide, which cases are worth issuing a warning.
So I believe (attention opinion) that compiler engineers would go the following way:
I would expect people to write code where either the result is casted to (unsigned char)
or where the outermost operator masks all higher bytes with a constant.
a = (unsigned char) ( /* some obscure bit-wise expressoin */ );
would be OK thena = 0xff & ( /* some obscure bit-wise expressoin */ );
also OKif you know that your compiler translates those two patterns correctly the other cases shouldn't bother you too much.
I've seen compilers that would issue a warning because of a = a | b;
so GCC not giving a warning is a free bonus. it might be, that gcc just infers the constant assignment in a | b
and therefore replaces it with 0xff | 0xff
which is known to work without problems. If that happens though I don't know why it cannot derive the constant value of a
in the other statements.
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