Reputation: 1703
During work i saw the following code snippet and now i wonder, if there is a reason for casting the "case-values" to a larger datatype. I guess, that it is used to offer the possibility of having more than 256 different states later on, but then, the state variable must also be larger. Here is the code i am talking about:
#define STATE_1 (uint8_t)(0x00)
#define STATE_2 (uint8_t)(0x01)
...
#define STATE_n (uint8_t)(0x..)
void HandleState(uint8_t state)
{
switch(state)
{
case (uint16_t)STATE_1:
// handle state 1
break;
case (uint16_t)STATE_2:
// handle state 2
break;
...
case (uint16_t)STATE_n:
// handle state n
break;
default:
break;
}
}
Is there another reason for this?
Upvotes: 3
Views: 4053
Reputation: 213892
It looks like a slightly failed attempt to get rid of implicit integer promotions on a 8-bit or 16-bit microcontroller.
First of all, there is no way integer promotion can cause harm here, so preventing it is overly pedantic and just reduces readability. At a glance it looks like nonsense.
But.
Perhaps the coding standard used enforced that no implicit conversions are allowed? Which for example MISRA-C does. In that case, the code suddenly makes sense: they wished to surpress warnings from their static analysis tool.
Using explicit casts would then also be a way of demonstrating that you are actually aware of implicit type promotions (something that only a handful of C programmers are, sadly) and that you handle them in your code.
But if so, the programmer missed out one integer promotion taking place, namely here: switch(state)
. This is how switch statements work:
The integer promotions are performed on the controlling expression. The constant expression in each case label is converted to the promoted type of the controlling expression.
So if the programmer was concerned about implicit promotions, they should have written the code as switch((uint16_t)state)
and then also kept the casts in each case
.
If you sneered at the code in the question, consider the following:
uint8_t
will get promoted to a (signed) int
in this code?Upvotes: 3
Reputation: 385194
Is there another reason for this?
No.
It's either a mistake, muppetry, or legacy (perhaps state
and the macros used to be something else, but this particular code never got changed?).
I'm voting for muppetry, personally. Sometimes you run into code that somebody else wrote that is bad code, and that's just the way it is.
Upvotes: 6
Reputation: 12263
It might be intended to enforce unsigned int type promotion for the compares, but unit16_t is not guaranteed to be the same size either and just casting state would be sufficient.
Perhaps the state codes were enum labels in a previous version? These are by default int - but even then the casts make little sense imo.
Note that the casts even possibly suppress warnings about inappropriate size. Best would be to use an enum, or #define
the labels just unsigned, e.g. 0x00U
without fixing the type.
Upvotes: 1
Reputation: 13324
That just looks like bad style all around. You should have a single typedef for state:
typedef uint8_t State;
Then your code would look like this:
#define STATE_1 (State)(0x00)
#define STATE_2 (State)(0x01)
...
#define STATE_n (State)(0x..)
void HandleState(State state)
{
switch(state)
{
case (State)STATE_1:
// handle state 1
break;
case (State)STATE_2:
// handle state 2
break;
...
case (State)STATE_n:
// handle state n
break;
default:
break;
}
}
Then if you later find you need uint16_t
, you only need to change one line.
Upvotes: 1