C,复合赋值 - 算术运算,转换可能是松散的信息

时间:2015-11-27 10:47:13

标签: c

有没有办法将操作写入短路并抑制警告?

BYTE data[10];
int i = 0;    
int offset = 0;

for (i = 0; i < 7; i++) {
    // some code
    data[offset] |= (1 << i);  // WARNING: conversion may loose information
}

我的尝试:

data[offset] |= (BYTE) (1 << i); // failed
data[offset] |= (1 << (BYTE) i); // failed

编译器:西门子的TIA-V13 WinCC

解决方案:没有复合赋值运算符!

1 个答案:

答案 0 :(得分:4)

您没有定义BYTE;我假设它与stdint.h s uint8_t相同(应始终优先于自制类型)。

a |= b(粗略地)转换为a = a | b,包括整数促销,作为常规算术转换的一部分。对于给定的类型,这意味着在执行操作之前a将转换为int,从而产生int结果。最终的赋值将截断此int作为赋值,可能会丢失信息(可能是符号),因为int至少为16位宽。

转换b没有帮助,因为转换是针对操作完成的,您必须转换结果。

转型也是解决方案:

uint8_t a;
a = (uint8_t)(a | b);

明确地告诉编译器你知道你做了什么并闭嘴。只要确保你真的知道你做了什么!

这不是很优雅,但是抑制警告的唯一方法。 OTOH的行为与简单的赋值版本在算术上是一致的。

编辑:在可能的情况下移位时应使用无符号整数常量。更重要的是,无论如何你操作无符号变量。作为一般规则,尽量避免混合有符号和无符号操作数。如果不可能,请确保您知道发生了什么并捕获所有无效案例。

Edit2:对于某些实现/有符号整数表示以及类型和操作的某些组合,可以证明不会丢失任何信息,因此警告已过时。但是,这似乎需要知道机器详细信息,这些信息在生成警告的阶段可能无法获得。

也许C标准应该定义复合赋值以隐式包含最终的强制转换。那不是唯一的遗产。 OTOH,这种行为可能会给那些没有意识到这一点的人带来另一个方向的混淆(请注意,在C中,赋值会产生结果!)。两个邪恶中哪一个较小?