Почему g++ или clang не выдают предупреждение при усечении неконстантной переменной, присваивая ее переменной меньшего типа?

И clang 2.9, и g++ 4.1.2 сгенерируют предупреждение, когда переменная x объявлена ​​постоянной в фрагменте кода ниже. Однако при удалении 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 ++ предоставляет сообщение " предупреждение: большое целое число неявно усекается до беззнакового типа " и предупреждение "лязг" : неявное преобразование из "const unsigned int" в "const unsigned char" меняет значение с 1000 на 232 [-Wconstant-преобразование] ".

Есть ли способ автоматически обнаружить этот случай, не проверяя код вручную и не полагаясь на правильно спроектированные модульные тесты?

3 ответа

Решение

Для GCC добавьте флаг -Wconversion и вы получите желаемое предупреждение. Это не часть -Wall поскольку так много кода просто игнорирует эти типы вещей. Я всегда включаю его, так как в противном случае обнаруживаются трудности при отладке дефектов.

Если это const, компилятор может увидеть его значение и предупредить об усечении. Если это не const, он не может, несмотря на инициализацию. Это:

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

эквивалентно:

const unsigned char c = 1000;

Я запустил gcc с -O3 -fdump-tree-vrp, и в дампе я вижу следующее:

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);

то есть он просто указывает на константы 1000 и 232 в выражении cout!

Если я запускаю его с -O0, он ничего не выводит, несмотря на ключи -ftree-vrp и -ftree-ccp.

Похоже, что gcc вставляет константы, прежде чем он сможет выдавать предупреждения...

Другие вопросы по тегам