代码之家  ›  专栏  ›  技术社区  ›  Khen

MISRA-C:2012年规则10.8“被转换为更广泛类型”的警告

  •  2
  • Khen  · 技术社区  · 7 年前

    我收到了关于规则10.8的MISRA-C警告: “基本无符号”类型(无符号字符)的复合表达式正在转换为更广泛的无符号类型“无符号短”。

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

    void Fucntion(unsigned char isSwitchOn) {
        unsigned short switchMask = 0U;
    
        switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
    

    为什么检测到警告? 此外,此代码是否会导致问题?

    我认为表达式(isSwitchOn&1U)被转换为int类型并进行计算,结果被截断并存储为无符号短类型。这样想,我觉得这个警告很不自然。

    3 回复  |  直到 7 年前
        1
  •  1
  •   chux    7 年前

    为什么检测到警告?

    让我们看看

    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. isSwitchOn & 1U ,结果类型为 未签名 .

    3. 铸造 (unsigned short) 未签名 结果-这一步似乎很奇怪。 这是MISRA-C警告 第10.8条。不需要演员阵容。这个 复合型 未签名 不必要地缩小到 unsigned short .

    4. 这个 (无符号短) 结果已为换档和 整数促销 对的每个操作数执行 << . 所以 (无符号短) 被提升为 int 或者可能 未签名 如果 USHRT_MAX > INT_MAX . 让我们假设 整数 .

    5. 现在 整数 发生。结果是类型 整数 .

    6. 这个 应用于 .


    此外,此代码是否会导致问题?

    我不明白 在这个 WET 编程。结果如何 unsigned switchMask ,是的,则移位的位将丢失。

    在换班后公布结果更有意义。 @Myst

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

    或避免其他潜在警告

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

    (isSwitchOn & 1U) 转换为int类型并计算

    不,表达式 (unsigned short)(isSwitchOn & 1U) 转换为int类型并进行计算。


    注:值得怀疑的是 unsigned char isSwitchOn unsigned short switchMask 不是同一类型。

        2
  •  0
  •   user3629249    7 年前

    关于:

    unsigned short switchMask = 0U;
    

    此语句正在分配 unsigned short int 使用 unsigned int

    关于:

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

    本声明为a 无符号短整型 用一个 无符号整型

        3
  •  0
  •   Lundin    7 年前

    Chux发布了一个答案,解释了代码发生了什么以及为什么它是错误的。至于如何修复它,你必须重写它。有两个问题:

    • 您将字符类型用作布尔值,然后在算术中也使用该字符类型,将类型转换为升迁后的类型,而不是升迁前的类型。据说这样做是为了去掉额外的分支。
    • 您使用的是C的本机整数类型,它可以有任何大小。这不是推荐做法,违反了MISRA-C:2012第4.6条。摆脱这些类型并使用 stdint.h 相反,它允许您编写确定性的、可移植的代码。

    现在有两种方法来处理隐式类型的提升:要么你让它们发生,然后再投——这通常是米斯拉喜欢的。或者根本不让它们发生,在计算操作之前强制转换为宽无符号类型,从而消除隐式提升。就米斯拉而言,任何一个都可以;我个人更喜欢后者。

    固定代码如下所示:

    // 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——任何地方都不会发生隐性升级。

    更多信息: Implicit type promotion rules .