GCC和-Wconversion

时间:2019-01-15 08:50:18

标签: c++ gcc language-lawyer

让我们编译以下程序:

int main()
{
    uint16_t data = 0;
    data |= uint16_t(std::round(3.14f));
    return 0;
}

g++ -Wconversion prog.cpp

我们会得到warning: conversion to ‘uint16_t {aka short unsigned int}’ from ‘int’ may alter its value,但在这里看不到隐式转换。

此类警告应通过显式强制转换忽略,例如:

double d = 3.14;
float foo1 = d; // Warning
float foo2 = float(d); // No warning
float foo2 = static_cast<float>(d); // No warning

GCC在这里还是一个错误?

请注意,我的代码段很小。例如,在以下情况下警告会消失:

  • f中删除3.14后缀,即设为double
  • 使用分配而不是|=
  • 删除std::round
  • 缓存舍入结果:const auto r = uint16_t(std::round(3.14f));,然后将其或分配给data

2 个答案:

答案 0 :(得分:1)

  

GCC在这里还是一个错误?

由于行为与预期不符,因此我将其称为错误。

https://godbolt.org/z/aSj--7看来,在海湾合作委员会看来,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维护者的疏忽。

答案 1 :(得分:1)

The warning is bogus.

According to [over.built]/22:

For every triple (L, VQ, R), where L is an integral type, VQ is either volatile or empty, and R is a promoted integral type, there exist candidate operator functions of the form ...

VQ L&   operator|=(VQ L&, R);

So we get a built-in unsigned short operator |=(unsigned short&, unsigned int);

There are no implicit conversions in the given expression

uint16_t data = 0;
data |= uint16_t(std::round(3.14f));