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