【问题标题】:Compiler warnings conversion编译器警告转换
【发布时间】:2014-10-20 12:05:00
【问题描述】:

我们使用启用了-Wconversion 的gcc 进行编译。当我离开下面isBitSet 函数返回的移位结果时,我收到以下警告。

警告:从 'int' 转换为 'u_int16_t {aka short unsigned int}' 可能会改变它的值 [-Wconversion]

#include <stdint.h>

using namespace std;

void convertToPos(uint16 in) {

    auto isBitSet = [&in](uint8_t position) -> bool{
        return (in & (1 << position));
    };

    uint16_t signal = 0;
    signal |= isBitSet(1) << 9;  // Calibrated
    signal |= isBitSet(2) << 10; // Corresponds to digital map
    signal |= isBitSet(5) << 13; // DR
    signal |= isBitSet(8) << 15; // 3D Fix

}

int main(int argc)
{
    convertToPos(4);
    return 0;
}

我尝试将 lambda 更改为以下,但仍然出现相同的错误。我该如何解决?

auto isBitSet = [&in](uint8_t position) -> uint16_t {
    return (in & (1 << position)) ? 1u:0u;
};

【问题讨论】:

    标签: c++ gcc compiler-warnings integer-promotion


    【解决方案1】:

    为避免警告,您可以这样做:

    signal = uint16_t(signal | isBitSet(1u) << 9);
    

    因为operator | 将运算符uint16_t 提升为int

    【讨论】:

    • 更好,IMO,应该是signal |= uint16_t(isBitSet(1) &lt;&lt; 9);。 (同样,升级仍然发生,从技术上讲,您确实将int 隐式转换为uint16_t,但GCC 应该意识到uint16_t | uint16_t 的结果总是可以安全地分配给另一个uint16_t。)
    • @hvd:我仍然对signal |= uint16_t(isBitSet(1) &lt;&lt; 9); 发出警告:-( (gcc 4.8.1)。
    • 嗯。测试表明你是对的。 signal |= uint16_t(...) 发出警告,signal = signal | uint16_t(...) 不发出警告。使signal |= uint16_t(...) 变得更好(同样,IMO)的原因是避免重复signal,但这似乎是不可避免的。
    【解决方案2】:

    在这种情况下,移位运算符按位包含或运算符都将integer promotions应用于它们的操作数,因为uint16_t可以用int 操作数被提升为 int,因此gcc 警告您可能会导致从较大类型 intuint16_t 的转换损失惨重。

    处理这个问题的 C++ 方法是使用static_cast,它看起来像以下工作:

    signal = signal | static_cast<uint16_t>(isBitSet(1) << 9);
    

    看起来不需要强制转换| 的结果,虽然严格来说它应该与&lt;&lt; 没有什么不同,但我猜gcc 能够推断出在这种情况下它是可以的。从技术上讲,这更好:

    signal = static_cast<uint16_t>( signal | isBitSet(1) << 9);
    

    供参考5.8 中的 C++ 标准草案 Shift 运算符 说:

    操作数应为整数或非范围枚举类型,并且 进行积分促销。[...]

    5.13 部分 按位包含 OR 运算符 说:

    执行通常的算术转换;[...]

    在这种情况下,通常的算术转换最终会应用 整数提升

    【讨论】:

      【解决方案3】:

      这不是错误。它的意思是,通过将整数转换为无符号整数,如果整数为负数,值将发生变化。这真的没有“解决办法”。您只需要小心 unsigned 从签名中获取的值。我猜你正在使用无符号,因为它需要为 0 及以上,所以如果有的话,这将修复任何意外输入的负值。

      【讨论】:

        猜你喜欢
        • 2021-11-16
        • 2011-10-15
        • 2011-05-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-15
        • 1970-01-01
        相关资源
        最近更新 更多