2011-11-06 15 views
29

Nie mogę znaleźć odpowiednich części w standardzie C w pełni definiujących zachowanie operatora jednoargumentowego minus z niepodpisanymi operandami.C: jednoargumentowe zachowanie operatora minus z niepodpisanymi operandami

z 2003 C++ Standard (tak, C++, pokrywa się ze mną przez kilka linii) mówi w 5.3.1c7: The negative of an unsigned quantity is computed by subtracting its value from 2^n, where n is the number of bits in the promoted operand.

Standard 1999 C, jednak nie obejmuje takiego wyraźnego oświadczenia i nie jednoznacznie definiuj jednoargumentowe zachowanie, ani w 6.5.3.3c.3, ani w 6.5c4. W drugim z nich jest napisane: Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, ...) ... return values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed types.), co wyklucza jednoargumentowy minus i wydaje się, że rzeczy pozostają niejasne.

This earlier question odnosi się do K & książki R ANSI C, sekcja A.7.4.5, która mówi The negative of an unsigned quantity is computed by subtracting the promoted value from the largest value of the promoted type and adding one.

Jaki byłby standard z 1999 r. Odpowiadający powyższemu cytatowi z książki?

6.2.5c9 mówi: A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

Czy o to chodzi? Czy jest jeszcze coś, czego mi brakuje?

+1

Tak, jest to §6.2.5. –

+1

Wyniki operatorów '<<' and '>>' nie zależą od reprezentacji liczb całkowitych. Są one definiowane jako mnożenie i dzielenie potęgami dwóch i są dobrze określone tylko dla nieujemnych argumentów. "<<" jest niezdefiniowane dla ujemnych operandów, a '>>' jest zdefiniowane przez implementację dla ujemnych operandów. –

+0

"Wartość ujemna niepodpisanej ilości jest obliczana poprzez odjęcie promowanej wartości od największej wartości promowanego typu i dodanie" - wiem, że moje matematyczne kung fu jest słabe w porównaniu do potężnego Ritchiego i Stroustrupa, ale wydaje się, że biedny, a może i szalony, sposób poradzenia sobie z sytuacją, która z pewnością jest błąd programisty 99,9 ...% czasu. Dlaczego nie rzucić błędu kompilacji mówiąc, że "próbowałeś zastosować znak do typu bez znaku, ty dingus"? – CCJ

Odpowiedz

14

Tak, 6.2.5c9 jest dokładnie tym akapitem, którego szukasz.

+3

Alternatywnie, można zobaczyć operatora negatywu jako zapewniający odwrotność jego operandu. Jeśli N jest bez znaku, -N jest równoważne 1U + ~ N, ponieważ jest to wartość, która po dodaniu do N da zero. – supercat

+0

@supercat Masz więc gwarancję zachowania uzupełnienia dwójki, nawet jeśli podstawowy sprzęt używa innej reprezentacji liczb ujemnych? – JAB

+0

@JAB: Reprezentacje dwójki uzupełniają się w przypadku niepodpisanych reprezentacji, ale definicja zachowania nie ma nic wspólnego z dwójką-dopełnieniem. – supercat

4

W każdej realizacji znam, negatywne jest obliczana jako two's complement ...

int a = 12; 
int b = -a; 
int c = ~a + 1; 
assert(b == c); 

... tak naprawdę nie ma fizycznej różnicy między negatywnymi podpisane i „negatywnych” liczb całkowitych bez znaku - jedyną różnicę to, w jaki sposób są one interpretowane interpretowane.

Więc w tym przykładzie ...

unsigned a = 12; 
unsigned b = -a; 
int c = -a; 

... The b i c będą zawierać te same bity. Jedyna różnica polega na tym, że b jest interpretowany jako 2^32-12 (lub 2^64-12), podczas gdy c jest interpretowany jako "normalny" -12.

Tak więc, wartość ujemna jest obliczana dokładnie w ten sam sposób, niezależnie od "znaku", a rzutowanie między znakiem bez znaku a podpisem jest w rzeczywistości operacją zerową (i nigdy nie może spowodować przepełnienia w pewnym sensie, że niektóre bity potrzebują być "odciętym").

+8

Wiem to wszystko z praktyki. Pytanie dotyczy innej rzeczy, zachowania zgodnego z normą. –

+0

Nie wiedziałem o tym i wydaje się, że to podstawa, ta. +1 –

5

Zachowanie jednoargumentowego operatora minus na niepodpisanych operandach nie ma nic wspólnego z tym, czy maszyna wykorzystuje arytmetyczną sumę dwójkową z podpisanymi liczbami. Zamiast tego, biorąc pod uwagę unsigned int x,y;, oświadczenie y=-x; spowoduje, że y otrzyma dowolną wartość, jaką musiałby posiadać, aby uczynić x+y równe zero. Jeśli x jest równe zero, y będzie podobnie zerem. Dla dowolnej innej wartości x, będzie to UINT_MAX-x+1, w którym to przypadku arytmetyczna wartość x+y będzie wynosić UINT_MAX+1+(y-y), która po przypisaniu do unsigned integer, będzie odjąć od niego UINT_MAX+1, dając zero.