GCC and -Wconversion

GCC and -Wconversion

本文关键字:-Wconversion and GCC      更新时间:2023-10-16

让我们编译以下程序:

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 就在这里还是一个错误?

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

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

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维护者的疏忽。

警告是假的。

根据[over.built]/22:

对于每个三元组(L,VQ,R),其中L是整型,VQ是易失性或空的,R是提升的整型存在以下形式的候选算子函数...

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

所以我们得到了一个内置unsigned short operator |=(unsigned short&, unsigned int);

给定表达式中没有隐式转换

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