2016-04-11 2 views
2

a + b переполняет 255 назад до 4, как и следовало ожидать, тогда c/2 дает 2, как я ожидаю. Но тогда почему последний пример не переполняется при оценке тех же двух шагов?C переполняется внутри уравнения?

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

uint8_t a = 250; 
uint8_t b = 10; 
uint8_t c = (a + b); 
uint8_t d = c/2; 
uint8_t e = (a + b)/2; 

std::cout << unsigned(c) << ", " << unsigned(d) << ", " << unsigned(e) << "\n"; 

4, 2, 130

+0

Вы можете найти [** this **] (http://ideone.com/WBVJ8t) интересно. Обратите внимание на тип выводимого параметра. – WhozCraig

ответ

2

Это называется интегральное продвижение. Сами операции выполняются в собственном целочисленном типе вашего процессора, int, который может содержать номера больше 255. В случае a+b результат должен быть сохранен в uint8_t, и именно здесь выполняется усечение. В последнем случае сначала происходит деление, которое выполняется как int, и результат может быть отлично сохранен в uint8_t.

+0

. Итак, я бы получил другой результат на разных процессорах в зависимости от их собственного размера int? – trapper

+0

Да, но 'int' должен всегда иметь возможность удерживать не менее 32767, поэтому в этом случае с 255 вы всегда получите тот же результат. – atturri

+0

@trapper Также обратите внимание, что обертка при переполнении определяется только для * unsigned * integers. Переполнение * signed * integers - неопределенное поведение. –

0
a+b

дает значение 260, который не назначен какой-либо uint8_t типа, так что вы хороши в последнем случае. Только когда вы оцениваете любое значение больше 255 до uint8_t, тогда происходит переполнение.

+0

'a + b' is 260, который переворачивается до 4. Вопрос в том, почему это не происходит с' (a + b)/2' – trapper

+0

@trapper Да, отредактировал мой ответ. 'a + b = 260', но 260 не присваивается никакому' uin8_t', который должен быть усечен/переполнен, чтобы стать 4 – Gopi

0

В следующем (a + b) не переполнение, компилятор распознает a и b как целочисленные типов, так что результаты добавления в целочисленном типе, результат этого выражения не ограничивается размером условий или факторов в выражении.

Предположим, что тип переменной, такой как a или b, в этом случае ограничивает результат только этим типом. Хотя возможно, было бы невозможно использовать такой язык. Представьте себе пять переменных, когда никакого рассмотрения типа не производится их суммой до 500 т это ..

uint8_t a = 98; 
uint8_t b = 99; 
uint8_t c = 100; 
uint8_t d = 101; 
uint8_t e = 102; 

сумма приведенных выше переменных == 500. Теперь ... в следующем результате любого выражения не может превышать размер одного из условий ...

int incorrect = (a + b + c + d + e); 

в этом случае (a + b + c) == 41 затем (41 + d + e) == 244. Это бессмысленный ответ .. альтернатива, что большинство людей признают, т.е.

(98 + 99 + 100 + 101 + 102) == 500; 

Это одна из причин, по которой преобразование типов существует.

Промежуточные результаты в выражениях не должны ограничиваться членами или факторами выражения, а результирующим типом, то есть значением lvalue.

0

@atturri является правильным. вот что происходит с вашими переменными в машинном языке x86:

REP STOS DWORD PTR ES:[EDI] 
MOV BYTE PTR SS:[a],0FA 
MOV BYTE PTR SS:[b],0A 
MOVZX EAX,BYTE PTR SS:[a] ; promotion to 32bit integer 
MOVZX ECX,BYTE PTR SS:[b] ; promotion to 32bit integer 
ADD EAX,ECX 
MOV BYTE PTR SS:[c],AL ; ; demotion to 8bit integer 
MOVZX EAX,BYTE PTR SS:[c] 
CDQ 
SUB EAX,EDX 
SAR EAX,1 
MOV BYTE PTR SS:[d],AL 
MOVZX EAX,BYTE PTR SS:[a] 
MOVZX ECX,BYTE PTR SS:[b] 
ADD EAX,ECX 
CDQ 
SUB EAX,EDX 
SAR EAX,1 
MOV BYTE PTR SS:[e],AL 
Смежные вопросы