Как правильно проверить переполнение при приведении к uint32_t - PullRequest
0 голосов
/ 15 мая 2019

Как мы можем правильно проверить и обработать переполнение , когда мы приведем к uint32_t, например:

long int val = <some value>
uint32_t new_val = static_cast<uint32_t>(val);

Если я попробую выше, я получу ожидаемое преобразованиеошибка:

ошибка: преобразование в 'uint32_t {aka unsigned int}' из 'long int' может изменить его значение [-Werror = преобразование]

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

Ответы [ 3 ]

1 голос
/ 15 мая 2019

Если используется , вы можете использовать boost::numeric_cast, найденный в .

uint32_t new_val = boost::numeric_cast<uint32_t>(val)

Ссылка на ссылку page .


Без вам придется выполнить проверку самостоятельно:

uint32_t new_val{static_cast<uint32_t>(val)};//<-- optimistic conversion, check for overflow next

const bool overflow = val > std::numeric_limits<uint32_t>::max() || val < std::numeric_limits<uint32_t>::min();

if (overflow) {
  //handle overflow, this could involve calling std::terminate, throwing an exception, or a truncation of the value (to zero)
}

Эту идею, конечно, можно воплотить в (ala. boost::numeric_cast), если необходимо, в более общем смысле.

0 голосов
/ 15 мая 2019

Проверка на переполнение действительно выполняется путем сравнения исходного значения с минимальными / максимальными значениями целевого типа (std::uint32_t). Но это еще не все - как вы собираетесь обрабатывать ситуацию, в которой исходное значение находится за пределами области целевого значения? В вашем случае отрицательный val уже поднимает этот вопрос, и это не затрагивает сценарий переполнения, поскольку отрицательные значения, назначенные целым типам без знака, хорошо определены (хотя полученное значение может не соответствовать ожидаемому).

Вот простое решение, характерное для long int до std::uint32_t:

#include <limits>

std::uint32_t new_val = val < 0 || val > std::numeric_limits<std::uint32_t>::max() ?
    0 : static_cast<std::uint32_t>(val);

Это безопасно и не должно выдавать предупреждения компилятора (-Wconversion), так как приведение является явным. Проблема заключается в том, что результирующее значение 0 представляет два состояния - неудачное преобразование, а также успешное преобразование, когда исходное значение val равно нулю. Чтобы смягчить это, C ++ 17 дает вам, например, std::optional. Перед этим вам потребуется дополнительная отправка по делу val == 0.

0 голосов
/ 15 мая 2019
long int val; // range -2,147,483,648 to 2,147,483,647
uint32_t new_val; // range 0 to 4,294,967,295

В вашей конверсии, когда val отрицательно, ваша конверсия дает неправильные значения.Ниже код работает без ошибок в c ++ 11 и c ++ 14.

#include <iostream>
#include <cstdint>
int main() { 
long int val = 1; // try with -1 too
uint32_t new_val = static_cast<uint32_t>(val);
std::cout << "val = "<<val<<std::endl;
std::cout << "new_val = "<<new_val<<std::endl;
return 0;
}

выполнение кода

...