MISRA-C:2012 规则 10.8 警告 "being cast to a wider type"

MISRA-C:2012 warning of Rule 10.8 "being cast to a wider type"

我收到规则 10.8 的 MISRA-C 警告: 'essentially unsigned' 类型(unsigned char)的复合表达式正在转换为更宽的无符号类型,'unsigned short'.

此警告是使用以下代码检测到的。

void Fucntion(unsigned char isSwitchOn) {
    unsigned short switchMask = 0U;

    switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;

为什么检测到警告? 另外,这段代码会导致问题吗?

我认为是将表达式(isSwitchOn & 1U)转为int类型计算,结果截断为unsigned short类型存储。这么想,警告对我来说似乎不自然。

关于:

unsigned short switchMask = 0U;

此语句正在使用 unsigned int

分配 unsigned short int

关于:

switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;

此语句正在将 unsigned short intunsigned int

相结合

Why was a warning detected?

让我们看看

void Fucntion(unsigned char isSwitchOn) {
  unsigned short switchMask = 0U;
  switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
  1. isSwitchOn,排名低于 1U,经过 通常的算术转换 (C11 §6.5.10 3)到类型 unsigned 以匹配 1U.

  2. 的类型 计算
  3. isSwitchOn & 1U,结果类型为unsigned.

  4. Cast (unsigned short) 应用于 unsigned 结果 - 这一步看起来很奇怪。 这是规则 10.8 的 MISRA-C 警告。不需要演员表。 复合类型 unsigned 不必要地缩小为 unsigned short

  5. (unsigned short) 结果准备移位,整数提升<< 的每个操作数执行。因此 (unsigned short) 被提升为 int 或者可能 unsigned 如果 USHRT_MAX > INT_MAX。让我们假设 int.

  6. 现在发生 int 的移位。结果类型为 int.

  7. int应用于unsigned short


Also, does this code cause problems?

我没有看到 在这个 案例中,导致问题的转换不是 WET 编程。如果结果是 unsigned switchMask,是的,那么移出的位就会丢失。

在移位后转换结果更有意义。

switchMask |= (unsigned short)((isSwitchOn & 1U) << 1);

或使用

避免其他潜在警告
switchMask = (unsigned short)(switchMask | ((isSwitchOn & 1U) << 1));

I think that the expression (isSwitchOn & 1U) is converted to an int type and calculated

不是,表达式(unsigned short)(isSwitchOn & 1U)转换成int类型计算


注意:unsigned char isSwitchOnunsigned short switchMask不是同一种类型是可疑的

Chux 发布了一个答案,解释了代码发生了什么以及错误的原因。至于怎么修,那就得重写了。有两个问题:

  • 您正在使用一个字符类型作为布尔值,然后您还在算术中使用该字符类型,在提升之后而不是在提升之前转换类型。据说这样做是为了摆脱多余的分支。
  • 您正在使用 C 的本机整数类型,它可以具有任何大小。这不是推荐的做法,并且违反了 MISRA-C:2012 Dir 4.6。摆脱这些类型并改用 stdint.h,这样您就可以编写确定性的、可移植的代码。

现在有两种方法可以处理隐式类型提升:要么让它们发生,然后再强制转换——这通常是 MISRA 更喜欢的方式。或者您根本不让它们发生,方法是在评估操作之前强制转换为宽无符号类型,从而消除隐式提升。就 MISRA 而言,两者都应该没问题;我个人更喜欢后者。

固定代码如下所示:

// ok if 8/16 bit system only
void Function (bool isSwitchOn) {
    uint16_t switchMask = ((uint16_t)isSwitchOn & 1U) << 1U;

// 32 bit system/fully portable code
void Function (bool isSwitchOn) {
    uint32_t shift = (uint32_t)isSwitchOn & 1U;
    uint16_t switchMask = (uint16_t) (shift << 1U);

请注意,这些示例应生成完全相同的机器代码。所以您也可以在 8 位系统上使用完全便携的版本。两者在给定系统上均符合 MISRA-C - 任何地方都不会发生隐式提升。

更多信息: