2014-02-10 1 views
2

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

#include <iostream> 

int main() 
{ 
    using namespace std; 

    unsigned int array[4]; 
    array[0]=4; 
    array[1]=4; 
    array[2]=2; 
    array[3]=-2; 

    cout << array[0] + array[1] + array[2] + array[3] << endl; 

    unsigned int b; 
    b=-2; 
    cout << b <<endl; 

    return 0; 
} 

Я ожидал, что в обоих случаях произойдет переполнение целых чисел. Однако только во втором случае это действительно произошло. В первом случае все велось так, как если бы это был массив целочисленных чисел, а не целочисленный массив без знака. Так что же происходит, что вызывает это аномальное поведение. Мой компилятор gcc 4.8 в случаях, имеющих какое-либо значение. Спасибо за помощь. EDIT: Вот-й выход на моем компьютере

8 
4294967294 
+0

Каков ожидаемый результат и каков фактический результат? –

+1

Целое переполнение *. * Происходит. Просто случается так, что вы довольны. Это не гарантирует работу, это просто обычное дело. –

+2

На самом деле, я уверен, что неподписанные правила переполнения и подписания -> без знака определены таким образом, что первый результат гарантированно равен 8, а второй результат гарантированно будет на 1 меньше максимального unsigned int. Это * подписан * переполнение, которое делает сумасшедшее дерьмо. – user2357112

ответ

7

Существует целочисленное переполнение. Вот причина (числа преобразуются в неподписанных Int)

1111 1111 1111 1111 1111 1111 1111 1110 // -2 
+0000 0000 0000 0000 0000 0000 0000 0100 //+ 4 
------------------------------------------- 
0000 0000 0000 0000 0000 0000 0000 0010 //= 2 
+0000 0000 0000 0000 0000 0000 0000 0100 //+ 4 
------------------------------------------- 
0000 0000 0000 0000 0000 0000 0000 0110 //= 6 
+0000 0000 0000 0000 0000 0000 0000 0010 //+ 2 
------------------------------------------- 
0000 0000 0000 0000 0000 0000 0000 1000 //= 8 -> the result 
0

Для знакового целого 31 бит рассматриваются как знаковый бит (при условии, 4 байта является целым числом размера). Для целых чисел без знака нет никакого знакового бита вообще, т. Е. Каждый бит вносит свой вклад в абсолютное значение

1

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

Отрицательные числа обычно представлены в форме дополнения 2. Таким образом,

11111110 is represented as −1 if signed 
11111110 is represented as 254 if unsigned 
1

когда вы (предполагая, что без знака ИНТ uint32_t):

array[0] = 4; 
array[1] = 4; 
array[2] = 2; 
array[3] = -2; // You store 4294967294 here 

И здесь array[0] + array[1] + array[2] + array[3] равно 4294967304, которые не подходят в uint32_t 0x1 0000 0008, которые приводят к 8.

0

Вы видите результат (определенного) неподписанного целочисленного переполнения. Ваше значение -2 становится очень большим целым без знака, которое при добавлении к другому целым без знака вызывает переполнение (результат больше, чем наибольшее возможное значение unsigned int) с эффектом , что результат на 2 меньше, чем другое целое без знака ,

Например:

unsigned int a = -2; 
unsigned int b = 4; 
unsigned int c = a + b; // result will be 2! 
1

Преобразование -2 в unsigned int результаты в значении 4294967294unsigned int составляет 32 бита в реализации C++, который вы используете).

unsigned int арифметика выполняется по модулю 4294967296 (или вообще UINT_MAX+1). Следовательно, в unsigned int, 4 + 4 + 2 + 4294967294 составляет 8.

Технически в соответствии со стандартом это не называется «переполнение», поскольку стандарт определяет результат, зависящий только от значения UINT_MAX. Переполнение - это неопределенное поведение, когда целочисленная арифметика со знаком превышает ее границы.

Смежные вопросы