Bitwise operations on enum types
While attempting to read data from memory into an enum via the following code, I got these weird results:
void read_memory (const unsigned, const unsigned, unsigned* const);
/* ... */
enum {DATA_0, DATA_1, DATA_2} data;
read_memory(base_addr, offset, &data); //data = 0x0900
data >>= 8; //data = 0x7e0000开发者_StackOverflow中文版00
I worked around this by introducing a temporary variable of unsigned type. But I'd like to be sure to understand why the previous method does not work.
First of all, I'm aware that the standard does not require a specific width for enum types, as long as all members can be represented. As a matter of fact, 6.7.2.2 states that:
Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type.
But since the raw data read from memory fits in a char, I think it should not be an issue. Moreover, if I understand correctly, "compatible" means that you can use it as if it were of such a type. In particular, objects of enumerated type can be operands of bitwise shift operators. I'm also aware that signedness may be a problem as we don't know if enum are signed or not. But, as far as I can tell, 0x0900 does not appear to be signed.
So where does the problem lie ?
How much data is read by your (badly named, in my opinion) read_memory()
function? If this isn't the same as the value of sizeof data
, you have a problem. Just because the enumerated values are small enough for a char
doesn't mean the compiler has to pick a single char
; perhaps instructions for manipulating int
-sized numbers are faster, and/or there are alignment issues.
After testing the code outside the debugger, it turned out that it behaved correctly and it was the information displayed by gdb that was inaccurate.
In fact, analyzing the disassembled machine code revealed that it did not match C source line numbers. As a result, the epilogue of the function was thought (by gdb) to be part of the data >>= 8;
instruction.
This issue remains strange to me since I compiled and linked all source and object files with -g -O0
.
Perhaps a bug in the compiler...
Edit: Actually it had nothing to do with gdb, it was the debug symbols emitted by the compiler that were erroneous.
Enum types are signed, so when you shift the sign bit (1) is copied over the numeric bits.
精彩评论