【问题标题】:GCC and -WconversionGCC 和 -Wconversion
【发布时间】:2019-01-15 08:50:17
【问题描述】:

让我们编译以下程序:

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

请注意,我的 sn-p 是最小的。例如,警告在以下情况下会消失:

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

【问题讨论】:

  • 更小的示例(不需要标头和函数)是short data(0); data |= short(float{3.0f});
  • @VTT 确实如此。在我的编译器上转载。

标签: c++ gcc language-lawyer


【解决方案1】:

GCC 是在这里还是一个错误?

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

https://godbolt.org/z/aSj--7看来,似乎在GCC的眼里,data |= uint16_t(std::round(3.14f))被翻译成

(void) (data = TARGET_EXPR &lt;D.2364, (uint16_t) round (3.1400001049041748046875e+0)&gt;;, data | NON_LVALUE_EXPR &lt;D.2364&gt;;)

TARGET_EXPR代表一个临时对象。D.2364是一个内部变量名。)

将 GCC 的内部语言翻译回 C++,我们会得到

data = (temp = (uint16_t) round (3.14e+0), data | temp)

由于逗号表达式的 LHS 不影响 RHS,这应该和 data = data | temp 一样安全。然而,GCC 警告前者而不是后者,这不太可能是故意的。因此,我认为这是对 GCC 维护者的疏忽。

【讨论】:

    【解决方案2】:

    警告是假的。

    根据[over.built]/22

    对于每个三元组 (L, VQ, R),其中 L 是一个整数类型,VQ 要么是 volatile 要么是空的,并且R 是提升的整数类型,存在形式为 ...

    的候选运算符函数
    VQ L&   operator|=(VQ L&, R);
    

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-11
      • 2015-06-03
      • 2020-12-27
      • 1970-01-01
      相关资源
      最近更新 更多