问题
I am doing embedded ARM programming with gcc 4.9. I've been using the -Wconversion
switch because it's in my company's default dev tool configuration. I'm using the stdint.h types (uint8_t, uint32_t, etc).
The compiler creates warnings every time I perform a compound assignment or even simple addition. For example:
uint8_t u8 = 0;
uint16_t u16;
// These cause warnings:
u8 += 2;
u8 = u16 >> 8;
The "common method" to fix this is to use casts, as discussed here and here:
u8 = (uint8_t)(u8 + 2);
u8 = (uint8_t)(u16 >> 8);
In addition to this being ugly, I keep running into convincing evidence that casting is generally bad practice.
My questions:
- Why is it bad to use typecasts in this way?
- Do I lose anything by simply omitting
-Wconversion
and letting the compiler do implicit conversions for me?
回答1:
The compiler is showing you potential problem spots, that you should consider changing, but not by casts. The problem in the code that you have is that in C, arithmetic is never done on type that are narrower than int
: the compiler always performs an implicit conversion to int
for them.
So effectively your code is converting the narrow unsigned types to int
, does the operation and then converts them back to the unsigned type.
Generally doing arithmetic with narrow types is not a good idea. Only use them if storage size is a problem (usually that would be larger structures such as arrays). For local, more or less temporary variables these narrow types make no sense.
回答2:
It's a matter of taste. A cast is never required by C when you assign a value of an arithmetic type to an object of a different arithmetic type. Some people uses the cast to document there is a hidden conversion and that they did it on purpose.
Personally I don't like to put extra useless stuff and I assume the reader knows the basics of C so I tend to avoid the cast (and I don't use -Wconversion
which is not a part of -Wall
or even -Wextra
anyway). Note that in an assignment if a literal on the right hand side cannot fit in the left hand side object gcc
usually warns (without -Wall
or -Wextra
) even if the assignment is not UB.
回答3:
The problem with casts is that they tell the compiler "shut up, I know what I'm doing", even if you don't. If someone decides that the variable must be able to handle values greater than 255 and changes the type to uint16_t, u8 += 2 would work, but u8 = (uint8_t)(u8 + 2) would be broken. Assuming that the variable isn't named u8 but "numberOfParagraphs", for example, that might be a bug that is very hard to find.
Better to use a bigger type in the first place. Unless you really, really want to store (u8 + 2) & 0xff, in which case you can write it that way and store it into a bigger variable without problems.
(Personally I would like an extension to the language like
(uint8_t)u8 += 2;
with the semantics that casting an lvalue to its own type has no effect and it remains an lvalue while removing the warning, but casting an lvalue to a different type would be an error. This would make it safe to shut up the compiler warning)
来源:https://stackoverflow.com/questions/32527685/using-typecasting-to-remove-gcc-compiler-warnings