从'int'类型转换为'short unsigned int'可能会更改其值 [-Wconversion]



我不明白为什么编译器(GCC)在这一行抛出[-Wconversion]警告(代码完美)。

uint16_t ICACHE_FLASH_ATTR crc(uint8_t data, uint16_t crc)
{
int i = 8;
crc = crc ^ (uint16_t)data << 8; // <-- here
do
{
if (crc & 0x8000)
crc = crc << 1 ^ 0x1021; // <-- here
else
crc = crc << 1; // <-- and here
} while (--i);
return crc;
}

所有操作数都是uint16_t,为什么要抱怨呢?

如果常量被计算为 int,我怎样才能摆脱警告(不禁用它们)。

我也尝试过但没有运气

crc = crc ^ (uint16_t)data << 8UL;

谢谢

假设一台机器具有sizeof(int) == 4CHAR_BITS == 8(如此sizeof(int) > sizeof(uint16_t),C 标准规定:

crc = crc ^ (uint16_t)data << 8;

经历"通常的算术转换",并且或多或少地被视为您编写的(8已经是一个int,因此不会被转换):

crc = (uint16_t)( ((int)crc) ^ (((int)((uint16_t)data)) << 8) );

正是将赋值中的异或运算符的int结果分配给uint16_t变量crc触发(准确)警告。

类似的评论适用于标记的其他两行中的每一行。

如果您在一台机器上工作sizeof(int) == sizeof(uint16_t),您首先不会收到警告。

6.3.1.8 常用算术换算:

¶1 许多期望算术类型操作数的运算符会导致转换并产生结果 以类似的方式键入。目的是确定操作数的通用实数类型 和结果。对于指定的操作数,将转换每个操作数,而不更改类型 域,其对应的实数类型是公共实数类型的类型。除非 明确说明否则,常见的实类型也是对应的实数类型 结果,其类型域是操作数的类型域(如果它们相同), 否则很复杂。这种模式称为通常的算术转换

  • 。浮点省略...

  • 否则,将对两个操作数执行整数提升。然后 以下规则应用于升级的操作数:

    • 如果两个操作数具有相同的类型,则无需进一步转换。

    • 否则,如果两个操作数都有
    • 有符号整数类型或两个操作数都有无符号整数类型 整数类型,具有较小整数转换秩类型的操作数为 转换为具有更高等级的操作数类型。

    • 否则,如果具有无符号整数类型的操作数的秩大于或 等于另一个操作数类型的秩,然后操作数与 有符号整数类型转换为带无符号的操作数的类型 整数类型。

    • 否则,如果具有有符号整数类型的操作数的类型可以表示 具有无符号整数类型的操作数类型的所有值,然后 具有无符号整数类型的操作数将转换为 具有有符号整数类型的操作数。

    • 否则,两个操作数都将转换为无符号整数类型 对应于具有有符号整数类型的操作数的类型。

6.3.1.1 布尔值、字符和整数 说:

¶2 ...如果int可以表示原始类型的所有值(受宽度限制,则 位字段),该值转换为int;否则,它将转换为unsigned int。这些称为整数促销58)所有其他类型均保持不变 整数促销。

58)整数提升仅适用于:作为通常算术转换的一部分,适用于某些 参数表达式,一元运算符+-~运算符的操作数,以及 shift 运算符,由其各自的子句指定。

§6.3.1.1¶1 非常详细地定义了"秩",但基本上较大的类型比较小的类型具有更高的秩(因此long的秩高于signed char)。

然后,您可以找到各种运算符的规格:

6.5.7 按位移位运算符:

每个操作数应具有整数类型。

对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。

6.5.11 按位独占 OR 运算符:

每个操作数应具有整数类型。

通常的算术转换是在操作数上执行的。

6.5.16 赋值运算符

赋值运算符将值存储在由左操作数指定的对象中。赋值表达式在赋值111) 之后具有左操作数的值,但不是左值。赋值表达式的类型是左操作数在左值转换后的类型。

111)允许实现读取对象以确定值,但不是必需的,即使 当对象具有可变限定类型时。

6.5.16.1 简单分配:

在简单赋值 (=) 中,右操作数的值被转换为 赋值表达式并替换存储在左侧指定的对象中的值 操作数。

最新更新