让我们编译下面的程序:
int main()
{
uint16_t data = 0;
data |= uint16_t(std::round(3.14f));
return 0;
}
用 g++ -Wconversion prog.cpp
我们会收到警告:从“int”转换为“uint16_t {aka short unsigned int}”可能会改变它的值
,但我在这里看不到隐式转换。
这种警告应该通过显式强制转换来消除,例如:
double d = 3.14;
float foo1 = d; // Warning
float foo2 = float(d); // No warning
float foo2 = static_cast<float>(d); // No warning
GCC 就在这里还是一个错误?
请注意,我的代码片段是最小的。例如,警告在以下情况下消失:
- 从
3.14
中删除f
后缀,即使其成为double
- 使用赋值代替
|=
- 移除
std::round
- 缓存舍入结果:
const auto r = uint16_t(std::round(3.14f));
,然后将其或赋值给data
。
最佳答案
Is GCC right here or it's a bug?
由于行为与预期不符,我将其称为错误。
来自 https://godbolt.org/z/aSj--7 ,似乎在GCC眼里,data |= uint16_t(std::round(3.14f))
翻译为
(void) (data = TARGET_EXPR <D.2364, (uint16_t) round (3.1400001049041748046875e+0)>;, data | NON_LVALUE_EXPR <D.2364>;)
( TARGET_EXPR
代表一个临时对象。D.2364
是一个内部变量名。)
将GCC的内部语言翻译回C++,我们会得到
data = (temp = (uint16_t) round (3.14e+0), data | temp)
由于逗号表达式的 LHS 不影响 RHS,这应该与 data = data | temp
一样安全.但是,GCC 对前者发出警告而不对后者发出警告,这不太可能是故意的。因此,我认为这是 GCC 维护者的疏忽。
关于c++ - GCC 和 -W 转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54195424/