2012-06-04 20 views
7

Językiem, którego używam jest C. Typ x i n to int.Różnica między ~ (x-1) i ~ x + 1, gdy x = 0x80000000

że jeden kod liniowy następująco

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

To pokazuje wartość X, n oraz dwie metody przeniesienia n bitów liczby dopełniacza x. Gdy x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000, ale gdy przesunąć te dwa o n bitów, wyniki są różne.

btw, gdybym zmienił 0xffffffff do ~ 1 + 1 (czyli ~ (x + (~ 1 + 1)), wynik jest taki sam jak ~ X + 1

Zastanawiam się, dlaczego tak się stało. Dzięki .

+0

[Czy "(uint16_t) -1" przenośny kod C?] (Http://embeddedgurus.com/barr-code/2011/06/is-uint16_t-1-portable-c-code/) – Lundin

+0

@Lundin Ten artykuł jest błędny. '(uint16_t) -1' ** jest ** gwarantowane przez standard w celu utworzenia' 0xFFFF', jeśli implementacja dostarcza tego typu w 'stdint.h'. (Oczywiście, nic nie jest gwarantowane, jeśli jest to twój własny typedef.) Nie ma dwuznaczności, typy o stałej szerokości są wymagane, aby nie mieć bitów dopełniających, więc nie jest to nawet ograniczone do bitów wartości (dobrze, jest, ponieważ istnieje są tylko bitami wartości w 'uintN_t'). –

Odpowiedz

4

Teraz usunięta odpowiedź Pavana Manjunatha miała poprawną odpowiedź dla jednego przypadku, przy założeniu, że int jest jak zwykle typem 32-bitowym. Stałej całkowitej

0xffffffff 

ma wartość 2^32 - 1 i nie jest zakodowania przez int, ale się przedstawić jako unsigned int. Tak więc jego typ to unsigned int (6.4.4.1). Stąd x przekształca się unsigned int do dodawania i

((~(x+0xffffffff))>>n) 

ocenia jako

((~(0x80000000u + 0xffffffffu)) >> n) 
((~0x7fffffffu) >> n) 
(0x80000000u >> n) 

wartością 2^(31-n) jeśli 0 <= n < 32 (to zachowanie niezdefiniowane jeśli n poza tym zakresie).

Na drugim przypadku odpowiedź ouah jest prawidłowa, gdy x = 0x80000000 jest int, ~0x8000000 = 0x7fffffff = INT_MAX i INT_MAX + 1 jest niezdefiniowane zachowanie jako liczba całkowita ze znakiem przepełnienia.

Niemniej jednak, typowym zachowaniem jest zawijanie, a następnie wynikiem dodawania jest liczba całkowita ze znakiem 0x80000000, a prawostronne liczby całkowite ujemne to zachowanie zdefiniowane w ramach implementacji (6.5.7). Często się zmienia wraz z rozszerzeniem znaku, co dałoby wynik -2^(31-n), który następnie jest interpretowany jako unsigned int o wartości 2^32 - 2^(31-n) przez specyfikator konwersji %xprintf.

+0

to ~ 0 podpisane lub niepodpisane ... – shirley

+0

'0' jest reprezentowalne jako' int', więc typ '~ 0' to również' int'. –

1

Gdy x = 0x80000000 ~ (x + 0xFFFFFFFF) = 0x8000000, ~ x + 1 = 0x80000000,

w systemie 32-bitowy int (zakładając x jest typu int) i podpis uzupełnienia uzupełnienia dwójkowego, to wyrażenie:

~x+1 

jest niezdefiniowanym zachowaniem. x = 0x80000000 oznacza ~x == 0x7FFFFFFF == INT_MAX i INT_MAX + 1 jest niezdefiniowanym zachowaniem. Więc ~x + 1 może być 0x80000000 lub cokolwiek innego.

Wyrażenie:

~(x+0xffffffff) 

z drugiej strony jest określona (0xffffffff jest unsigned int w C) i jest równa 0x80000000. Jest tak naprawdę zdefiniowany, ponieważ 0xffffffff jest liczbą całkowitą bez znaku, nigdy nie jest przepełniony w rozumieniu standardu C.

To oznacza, że ​​to stwierdzenie:

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

wywołuje niezdefiniowanej zachowanie i nie ma sensu, aby porównać oba rezultaty.

0

(Zakładając sizeof (int) wynosi 4, tj. 32-bitową wartość podpisu). 0x80000000; // -2147483648 która jest możliwie najmniejsza ujemny Int 0xFFFFFFFF // wynosi -1

Dodanie dwóch razem powoduje „wrap around” z ujemnej na dodatnią 0x7fffffff jest sumą dwóch (za pomocą int arytmetyczna), który jest 2147483647

Korzystanie z „~” operatorowi na 0x7fffffff daje completent bitową lub 0x80000000

Jeśli zaczniesz z dowolnej wartości int i odjąć 1 od niego (lub dodać 1 do niego, to nie robi materii) wystarczająco dużo razy, spowodujesz, że odwróci swój znak. Jest to podstawowy problem z arytmetyką z ustaloną precyzją.

W twoim przypadku nie można oczekiwać, że operatory arytmetyczne i bitowe będą ze sobą mieszać, nie zwracając jednak uwagi na to ograniczenie.

Należy również zwrócić uwagę, że asymetria występuje w arytmetyce uzupełnień 2: jest jeszcze jedna liczba ujemna od dodatniej (ponieważ trzeba reprezentować zero, co pozostawia nieparzystą liczbę innych reprezentacji bitowych dla pozostałych wartości).

Powiązane problemy