gcc имеет полезный флаг -Wconversion
, который выдает предупреждение, когда подразумевается переход от более широкого к более узкому типу, потенциально теряющий информацию. К сожалению, он имеет следующее... бесполезное... поведение.
Рассмотрим эту программу:
int main(void) {
short x = 1;
x = x+x;
return 0;
}
Компиляция с помощью -Wconversion производит
nonsense.c: In function 'main':
nonsense.c:3:8: warning: conversion to 'short int' from 'int' may alter its value [-Wconversion]
что справедливо; на большинстве платформ это будет делать то, чего вы не ожидаете, если это произойдет, если x==0x8000
. (Фактический механизм, с помощью которого вы получаете это предупреждение: операнды до +
подчиняются "обычным арифметическим преобразованиям", что расширяет их до int, поэтому результат также имеет тип int, а затем возврат к x
неявное преобразование от более широкого к более узкому типу.) Но предположим, что вы ожидаете и намерены это поведение. (Вы имитируете 16-разрядный процессор или 16-разрядный регистр сдвига или знаете диапазон возможных значений x
в этом коде, и он никогда не будет переполняться.) Вы можете сказать компилятору, вставив явное выражение:
int main(void) {
short x = 1;
x = (short)(x+x);
return 0;
}
и тогда он не будет жаловаться.
До сих пор так хорошо. Но если назначение, вызывающее проблему, является сложным назначением - +=
, *=
, <<=
и т.д. - тогда, насколько я вижу, нет способа избавиться от этого предупреждения, потому что есть 't любая точка в коде, в которую вы могли бы вставить явный приведение.
Это означает, например, что вы не можете иметь все
- -Wconversion в флагах компилятора верхнего уровня вашего проекта, чтобы уловить все реальные ошибки, на которые он предназначался.
- Любой экземпляр в любом месте кода сложных операторов присваивания, примененный к целым типам короче
int
. - Без предупреждения.
который кажется печальным.
Итак, вопрос: есть ли хороший способ обойти это? Я вижу следующие способы:
- Используйте
#pragma GCC diagnostic ...
, чтобы отключить предупреждение в битах кода, которые, как известно, провоцируют его, несмотря на отсутствие ошибок. (Даунсайд: уродливый, специфичный для компилятора.) - Разверните составные назначения в более длинные одиночные задания и вставьте явные приведения. (Даунсайд: супер-уродливый.)
- Отключить
-Wconversion
. (Даунсайд: это предупреждение полезно в других местах.) - Положите предупреждения. (Даунсайд: Несовместим с использованием
-Werror
; в любом случае, это хорошая практика, чтобы ваш код не компилировался без каких-либо предупреждений, потому что разница между "никакими предупреждениями" и "некоторыми предупреждениями" легче определить, чем разница между "некоторыми предупреждения" и "еще несколько предупреждений".)
Все это кажется неудовлетворительным, и мне интересно, есть ли что-то умнее, что мне не хватает.
(Примечание: конечно, я соглашусь "нет, что это" ответ, если это правда.)
Итак, похоже, что ответ заключается в том, что это действительно намеченное поведение, и нет способа остановить его намного лучше, чем перечисленные выше. (Mark B заметил, что вы можете написать функцию, которая делает то же самое, что и +=
, но с явным литьем. Ecatmur предложил определить новый тип с функциями operator+=
, чтобы делать явное кастинг.)
Я принимаю ответ Марка Б; фактический ответ на вопрос в названии просто "да": -).