2009-09-12 18 views
8

Nie dostaję tego!unsigned long 0 <-1?

#include <stdio.h> 

int main() 
{ 
    unsigned short t1 = 0, t2 = 0; 

    if(t1 < t2-1) 
     printf(" t1 < t2-1\n"); 

    unsigned long s1 = 0, s2 = 0; 

    if(s1 < s2-1) 
     printf(" s1 < s2-1\n"); 
} 

skutkuje:

s1 < s2-1 

Albo oba powinny zawieść lub oba nie. Próbowałem tego z gcc 4 & 4.2 4.2

+0

~ nairboon: Mam nadzieję, że nie masz nic przeciwko edycji. Kod, który zastąpiłem twój jest funkcjonalnie taki sam, ale można go skopiować/wkleić do edytora i skompilować bez zmian. –

+1

Należy pamiętać, że wynik ten nie jest gwarantowany. Na komputerach, na których int przechowuje ten sam zakres wartości, co krótki (wydaje się, że 16-bitowe komputery), zobaczysz dane wyjściowe dla obu znaków ifs, ponieważ promocja zamieni się wtedy na unsigned int, zamiast na int. –

Odpowiedz

12

Język C wykonuje „Powszechna arytmetycznych konwersje” Dla wielu podmiotów - w Konwersje są opisane w 6.3.1.8 standardu C99. W przypadku operandów zintegrowanych wykonywane są pierwsze promocje i to właśnie jest przyczyną problemu. Te promocje są opisane w 6.3.1.1 (arytmetyczne argumenty/logiczne, znaków i liczb całkowitych), który mówi między innymi:

Jeśli int może reprezentować wszystkie wartości tego samego typu, wartość jest konwertowana na int; w przeciwnym razie jest konwertowany na unsigned int. Są to tak zwane promocje bezpośrednie. Wszystkie pozostałe typy są niezmienione przez promocje całkowite.

W promocji są stosowane wyłącznie do obiektów lub wyrażenia z typem całkowitą z szeregu mniej niż int i unsigned int (lub bitfields).

Więc w exression:

t1 < t2-1 

chociaż zmienne są unsigned short są promowane na int, ponieważ na platformie int może reprezentować wszystkie wartości z unsigned short. Tak więc wyrażenie jest oceniane przy użyciu typów int i nie występuje niedopełnienie - część wyrażenia kończy się jako ujemna 1.

W wyrażeniu:

s1 < s2-1 

rodzaje unsigned long nie są promowane, ponieważ mają wyższą rangę „” niż int/unsigned int, więc wyrażenie jest oceniane przy użyciu arytmetyki bez znaku (z dolnego z odejmowanie) oraz s2-1 podwyrażenie ocenia bardzo dużej liczby, nie negatywnym 1.

jak litb wskazano w komentarzu, jeśli platforma nie int zaimplementowany jako typ 16-bitowy (co jest dozwolone - dla systemu MS-DOS przykład), pro ruch unsigned short byłby następujący: unsigned int zamiast int, ponieważ int nie byłby w stanie reprezentować wszystkich wartości unsigned short (unsigned short musi mieć co najmniej 16 bitów). W takim przypadku oba oświadczenia będą miały wartość true.

13

Nie jestem pewien, ale podejrzewam, że wyrażenie t2-1 automatycznie rozszerza się na wartość int. Nie mam tutaj standardu c, jakie są dokładne reguły konwersji, ale uważam, że typy mniejsze niż int są automatycznie poszerzane.

+3

+1, w wyrażeniu arytmetycznym, obiekty typów (podpis/unsigned) krótkie i (podpisane/unsigned /) char są * promowane * do int. – avakar

+1

Ta odpowiedź byłaby znacznie lepsza, gdybyś powiedział, że ** 't2' ** jest konwertowane na int, a nie **' t2-1' ** (więc jasne jest, że konwersja ma miejsce * przed * odejmowaniem). –

3

C przymusu, jak się odkrywasz, nie zawsze są oczywiste, kiedy operujesz pomiędzy różnymi typami. t2 jest u16, 1 jest (prawdopodobnie 32-bitowy), więc t2-1 jest dokładnie taką "operacją między różnymi typami" i powoduje ogólną koercję do int (ponieważ jest "dłuższa" niż u16 ...). Później, ponieważ s2 i 1 są zarówno 32-bitowe (choć o różnej sygnaturze), całkowity przymus jest niepodpisany długo. Tak więc rozmiary poszczególnych typów pomagają w ustaleniu sygnatury całkowitego przymusu.

sugeruję unikanie mieszanym signedness operacje (przez odlewanie lub specjalnego dosłownym zapisem literały takich jak 1 że w przeciwnym razie będą musiały int typ i uczynić swoje życie potencjalnie skomplikowane i kod potencjalnie nieprzenośne (a idealnie wymieszany rozmiarze!); -).

0

-1 jest reprezentowane jako wszystkie 1s. Dlatego interpretowana jako unsigned, ma wartość 2^32-1, która jest wyraźnie większa od 0. Przypuszczam, że pierwsze porównanie jest rozszerzane do wykonywania arytmetyki podpisanej 32-bitami (być może z powodu "1" będącego podpisany int).

pamiętać, że poniższe dostanie się do printf, bo porównanie jest obecnie odbywa się w 16-bitowych bez znaku przestrzeni jeszcze:

u32 temp = t2 - 1; 
if(t1 < temp) 
    printf(" t1 < t2-1\n"); 
+4

Dosłowne 1 (typu 'int') jest konwertowane na' unsigned long' przed odejmowaniem. Ponieważ arytmetyka na typach bez znaku jest zawsze wykonywana modulo '2^k', dla specyficznego dla typu' k', wynikiem jest '2^k-1'. Reprezentacja -1 nie jest zaangażowana (i nie musi to być wszystko na niektórych architekturach). – avakar

+0

Reprezentacja wartości -1 dotyczy wyjaśnienia drugiej części: dlaczego 0 <-1 w unsigned longs. – Yuliy

+0

Nie, nie jest. Jak mówi avakar, '-N' -> unsigned jest czysto matematyczną operacją, która po prostu oblicza' UINT_MAX + 1 - N'. Żadna reprezentacja nie jest nigdzie oparta. –

Powiązane problemy