Какой самый элегантный способ обработать предупреждение компилятора о возможной потере данных - PullRequest
0 голосов
/ 03 октября 2018

В нашем большом проекте на C ++ мы стараемся не предупреждать, но людям часто лень об этом.Одна вещь, которую я постоянно исправляю, это предупреждения из кода, подобного следующему:

sizex = sizey = 32 * c_scale;

, выдающего

предупреждение C4244: '=': преобразование из 'double' в 'i16', возможная потеря данных

Где sizex и sizey имеют тип i16, а c_scale - двойное число.

Так что я постоянно изменяю строки такого кода на что-то вроде

sizex = sizey = i16(32 * c_scale);

чтобы убрать предупреждение.

Я бы сказал, что это делает код менее читабельным, поэтому я не рад этому, но это лучше, чем отключение предупреждения, и это лучше, чем иметьНа мой взгляд, куча предупреждений, скрывающих, возможно, более серьезные предупреждения.

У кого-нибудь есть более изящный или иной способ справиться с этой ситуацией?

Ответы [ 3 ]

0 голосов
/ 03 октября 2018

В составе CppCoreGuidelines есть библиотека поддержки, которая называется GSL .Они обеспечивают безопасный способ преобразования типов, таких как узкий_каст :

Заголовок для этого можно найти здесь: https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl_util

auto sizex = gsl::narrow<unsigned>(32 * c_scale);

Идея состоит в том,что если результирующий тип (unsigned здесь) недостаточно велик (или имеет нарушение знака), будет выдано исключение.

Это проверка во время выполнения.Если вы хотите избежать затрат на проверку во время выполнения, вы можете создать аналогичную функцию, которая выполняет проверку только во время отладки сборок (когда NDEBUG нас не определено) и удалить проверку для release сборок.

0 голосов
/ 03 октября 2018

Некоторые полезные рекомендации по удобочитаемости и удобству обслуживания:

Использование стандартных типов

Представьте, что я присоединился к вашему проекту.Я понятия не имею, что такое i16, равно как и библиотеки, на которые вы ссылаетесь.Но я знаю, что такое std::int16_t (находится в <cstdint>).Как и авторы библиотек.

Скрыть детали за абстракциями

Операция, которую вы здесь описываете, масштабирует целое число на некоторый коэффициент (скажем, double?).Дьявол кроется в деталях.Вы не можете преобразовать двойное обратно в целое число без потери данных, поэтому вам нужно вернуться к приведению, которое выглядит грязным и заставит будущих сопровождающих задаться вопросом, что вы делаете.

Итак, давайте создадимабстракция:

inline
auto scale_and_round_down(std::int16_t value, double scale) -> std::uint16_t
{
    auto scaled_value = value * scale;  // answer will be a double
    return std::int16_t(value * scale); // round down to nearest int
}

теперь наш код становится:

sizex = sizey = scale_and_round_down(32, c_scale);

, который выражает намерение без каких-либо сомнений.В сборке релиза scale_and_round_down будет встроено.Вы не будете платить за производительность таких абстракций.

0 голосов
/ 03 октября 2018

Я не знаю, какой у вас тип i16, потому что он не соответствует стандарту C ++ 11.Я предполагаю, что вы имеете в виду тип ìnt16_t от <cstdint>, так что 16-разрядное целое число со знаком и что ваши sizex и sizey имеют тип int16_t.

Ваш c_scaleэто какой-то double.Так что, вероятно, IEEE754 64 бит с плавающей точкой двойной точности.См. http://floating -point-gui.de / для получения дополнительной информации.Он имеет 53-битную мантиссу.

Как можно ожидать, что 53 бита уместятся без потерь (во всех случаях) в 16 бит?Принцип pigeonhole применяется и сразу же сообщает вам, что, поскольку 2 53 больше 2 16 , это не так.

Компилятор прав, чтобы предупредить вас.В самом деле, вы можете явный какой-то актерский состав, чтобы избежать этого предупреждения

И, эксплицирующий актерский состав, вы просто скажете своему читателю, что вам это известно.Возможно, сгенерированный машинный код не изменится ни с приведением, ни с преобразованием.

Возможно, у вашего конкретного компилятора могут быть другие способы отключить это предупреждение (возможно, некоторые #pragma)

Вы можете использовать более сложную технологию статического анализа (возможно, Frama-Clang ), чтобы провести более семантический анализ и доказать, что приведение не дает утечки точности.Осторожно, такие инструменты могут быть сложными в освоении!

Кстати, стандарт C ++ мало говорит о предупреждениях в целом (они - вещь "качества реализации").Вы можете принять решение игнорировать их (но на практике вы не должны).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...