在开关盒中铸造成更大的类型

Cast to larger type in switch case

在工作期间,我看到了以下代码片段,现在我想知道是否有理由将 "case-values" 转换为更大的数据类型。我想,它是用来提供以后有超过 256 个不同状态的可能性,但是,状态变量也必须更大。 这是我正在谈论的代码:

#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;
  }

}

还有其他原因吗?

这看起来很糟糕。你应该有一个状态的类型定义:

typedef uint8_t State;

那么您的代码将如下所示:

#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;
  }

}

那以后如果你发现需要uint16_t,只需要改一行就可以了

它可能旨在为比较强制执行 unsigned int 类型提升,但 unit16_t 也不能保证大小相同,仅转换状态就足够了。

也许状态代码在以前的版本中是枚举标签?默认情况下,这些是 int - 但即便如此,强制转换在我看来也没什么意义。

请注意,转换甚至可能会抑制有关大小不当的警告。最好是使用枚举,或者 #define 标签只是未签名,例如0x00U 没有固定类型。

Is there another reason for this?

没有

要么是错误、木偶戏,要么是遗留问题(也许 state 并且宏曾经是别的东西,但这个特定的代码从未改变过?)。

我个人投票支持布偶戏。有时您 运行 进入别人编写的错误代码,而事实就是如此。

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:

  • Do you actually know what implicit promotions there are in a switch statement and did you consider what impact they might have on this code?
  • Do you know the meaning of the integer promotion rules? Did you know and consider that an uint8_t will get promoted to a (signed) int in this code?
  • Do you use a coding standard and static analysis tools at all, yourself?