2015-04-22 2 views
9

Когда я компилирую следующий код с GCC:-Wconversion предупреждение при использовании оператора << = на неподписанные символ

int main() 
{ 
    unsigned char c = 1; 
    c <<= 1; // WARNING ON THIS LINE 
    return 0; 
} 

Я получаю это предупреждение:

conversion to ‘unsigned char’ from ‘int’ may alter its value [-Wconversion]

Зачем ? Что не так с этим кодом? На самом деле, могу ли я использовать oprator <<= в переменной unsigned char? Команда

Компиляция:

g++ test.cpp -Wconversion -o test.exe

+1

Это, мне кажется, является одной из тех ситуаций, которые «прокляты, если вы делаете и прокляты, если не хотите», как для авторов компиляторов, так и для пользователей. Как пользователь, то, что вы написали, является чистым и дает намеченный ответ и, как правило, совершенно безупречно. И ему не нужен дополнительный лингвистический беспорядок, чтобы усложнить его понимание. Как писатель-компилятор, технически сужается преобразование, поэтому предупреждение технически корректно. Но я не могу не чувствовать, что в этом контексте или аналогичных, связанных с «коротким» (что, предположительно, также вызывает предупреждение), предупреждение действительно не является конструктивным. –

ответ

8

Это верное предупреждение:

c <<= 1; 

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

c = c << 1 

и правила для << говорят, что операнды продвинуты и в этом случае будут повышены до int, и результат будет продвигаемого типа. Таким образом, в конце будет конверсия от int до unsigned char, что может привести к изменению значения.

Код действителен, предупреждение сообщает вам, что происходит неявное преобразование, а в некоторых случаях преобразование может изменить значение. Использование броска отключит предупреждение. Результаты неявных преобразований могут быть очень противоречивыми и в некоторых случаях неопределенным поведением. См. gcc Wconversion wiki for some details.

Я не вижу способ убрать предупреждение без расширения работы вручную и с помощью static_cast:

c = static_cast<unsigned char>(c << 1); 

Как видно из длинной нити на этом gcc bug report не каждый чувствует, что это полезный случай для этого предупреждения.

Для справки из раздела draft C++ standard5.8 операторов сдвига:

Операндов должны быть интегральным или незаданным типа перечисления и интегральных поощрения выполняются. Типом результат является то, что продвигаемым левым операндом [...]

и из раздела 5.17 Назначения и назначения соединения операторов:

поведение выражения вида E1 оп = E2 эквивалентен E1 = E1 op E2, за исключением того, что E1 оценивается только один раз. [...]

+1

У меня также есть проблема, если do 'c << = static_cast (1);'. Вы говорите, что в C++ нет оператора сдвига для 1 байтовых типов? : -/ – Caduchon

+4

См. [Почему короткое преобразование в int перед арифметическими операциями в C и C++?] (Http://stackoverflow.com/q/24371868/1708801) для обоснования того, почему операнды продвигаются к более широким типам , В основном потому, что это приводит к быстрому сгенерированному коду. –

Смежные вопросы