2015-08-06 2 views
2

Я не уверен, когда мне приходится беспокоиться о переполнениях при использовании неподписанных символов. Этот случай ясно:Операции 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 

ли одновременно и быть преобразованы, чтобы плавать, прежде чем делать вычитание?

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

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

ли все три переменные преобразуются плавать?

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

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

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

неподписанных операции никогда не переполнение, они просто обернуть вокруг. 'uint8_t c = a - b;' означает 'uint8_t c = (uint8_t) ((int) a - (int) b);' который создает завернутый результат после отливки –

+0

Чтобы добавить комментарий @ LưuVĩnhPhúc, переполнение плохо, очень плохо. Это неопределенное поведение. Целочисленные целые числа никогда не переполняются. Вместо этого они используют арифметику по модулю 2^n. –

+0

Также см. [Почему коротко преобразовать в int перед арифметическими операциями в C и C++?] (Http://stackoverflow.com/q/24371868/1708801) –

ответ

5

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

Prvalues ​​малых интегральных типов (такие как полукокс) могут быть преобразован в более крупного prvalues ​​целочисленных типов (например, Int). В частности, арифметические операторы не принимают типы, меньшие, чем int, как аргументы, и интегральные рекламные акции автоматически применяются после преобразования lvalue-to-rval, если это применимо. Это преобразование всегда сохраняет значение.

И:

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

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

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

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