为什么 g++ 或 clang 在通过将非常量变量分配给较小类型的变量来截断非常量变量时不引发警告

Why does not g++ or clang elicit a warning when truncating a non-const variable by assigning it to a variable of smaller type?

本文关键字:变量 常量 非常 类型 警告 小类 clang g++ 为什么 分配      更新时间:2023-10-16

当变量 x 在下面的代码片段中声明为常量时,clang 2.9 和 g++ 4.1.2 都会生成警告。但是,当 const 被删除时,就像它在代码片段中一样,即使使用以下我所知道的最严格的参数执行,编译器也不会生成警告:"-Wall -Wextra -pedantic -ansi"

为什么编译器不会推断并报告相同的警告,因为 x 不是易失性的,并且在类型转换之前不可能修改?

#include <iostream>
int main(int argc, char **argv)
{
    unsigned int x = 1000;
    const unsigned char c = x;
    const unsigned int x_ = c;
    std::cout << "x=" << x << " x_=" << x_ << std::endl;
    return 0;
}
使用 const 无符号 int x = 1000

; g++ 提供消息"警告:大整数隐式截断为无符号类型"和 clang "警告:从 'const unsigned int' 到 'const unsigned char' 的隐式转换将值从 1000 更改为 232 [-Wconstant-conversion]"。

有没有办法在不手动检查代码或依赖正确设计的单元测试的情况下自动检测这种情况?

对于 GCC,添加标志-Wconversion,您将收到所需的警告。这不是-Wall的一部分,因为如此多的代码只是忽略了这些类型的东西。我总是打开它,因为它发现否则很难调试缺陷。

如果它是一个常量,编译器可以看到它的值并警告截断。如果它不是常量,则不能,尽管进行了初始化。这:

const unsigned int x = 1000;
const unsigned char c = x;

相当于:

const unsigned char c = 1000;

我已经用 -O3 -fdump-tree-vrp 运行了 gcc,我在转储中看到的是:

std::__ostream_insert<char, std::char_traits<char> > (&cout, &"x="[0], 2);
D.20752_20 = std::basic_ostream<char>::_M_insert<long unsigned int> (&cout, 1000);
std::__ostream_insert<char, std::char_traits<char> > (D.20752_20, &" x_="[0], 4);
D.20715_22 = std::basic_ostream<char>::_M_insert<long unsigned int> (D.20752_20, 232);

即它只是在 cout 语句中内联常量 1000 和 232!

如果我用 -O0 运行它,它不会转储任何东西,尽管有 -ftree-vrp 和 -ftree-ccp 开关。

似乎 gcc 在发出警告之前内联常量......