uint8_t, когда они переполняются?

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

uint8_t a = 3;
uint8_t b = 6;
uint8_t c = a - b; // c is 253 

Однако, что здесь происходит:

float d = a - b; // d is -3

Оба a и должны быть преобразованы в число с плавающей запятой перед выполнением вычитания?

Или также в этом случае:

float e = (a - b) + (a - c);

Все три переменные преобразуются в числа с плавающей запятой?

Возможны ли случаи, когда может произойти переполнение, даже если присваиваемая переменная является числом с плавающей запятой? Являются ли правила одинаковыми, если e является числом с плавающей запятой, целым числом или чем-то еще?

Кроме того, что происходит в таком случае:

int a = std::abs(a - b);

person Jan Rüegg    schedule 06.08.2015    source источник
comment
неподписанные операции никогда не переполняются, они просто зацикливаются. uint8_t c = a - b; означает uint8_t c = (uint8_t)((int)a - (int)b);, который производит обернутый результат после приведения   -  person phuclv    schedule 06.08.2015
comment
Чтобы добавить к комментарию @LưuVĩnhPhúc, переполнение — это плохо, очень плохо. Это неопределенное поведение. Целые числа без знака никогда не переполняются. Вместо этого они используют арифметику по модулю 2^n.   -  person David Hammen    schedule 06.08.2015


Ответы (1)


Ваш случай не является результатом преобразования char-to-float, а связан с правилами целочисленного продвижения. Cppreference утверждает следующее (выделено мной):

Значения prvalue небольших целочисленных типов (например, char) могут быть преобразованы в значения prvalue более крупных целочисленных типов (таких как int). В частности, арифметические операторы не принимают в качестве аргументов типы меньше, чем int, а целочисленные повышения автоматически применяются после преобразования lvalue в rvalue, если это применимо. Это преобразование всегда сохраняет значение.

И:

unsigned char или unsigned short могут быть преобразованы в int, если они могут содержать весь диапазон значений, и unsigned int в противном случае.

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

То же самое относится к примеру std::abs: значения преобразуются перед вычитанием, и результат передается функциям.

Дополнительные сведения о рекламных акциях со знаком/без знака в арифметических операциях см., например, в этом ответе: https://stackoverflow.com/a/6770275/3198247

person anderas    schedule 06.08.2015