2010-11-16 15 views
11
while ((1U << i) < nSize) { 
     i++; 
    } 

Jakiś szczególny powód użycia 1U zamiast 1?Czy jest jakaś różnica między 1U a 1 w c?

+0

Kod ten pojawia się w kodzie źródłowym PHP w pliku [ zend_hash.c] (https://github.com/php/php-src/blob/02457554a35fbb96fd3f51caf7deab91ca32ecb2/Zend/zend_hash.c#L154-L156). –

Odpowiedz

13

W przypadku większości kompilatorów oba będą dawać wyniki z taką samą reprezentacją. Jednakże, zgodnie ze specyfikacją C, wynik operacji przesunięcia bitowego na podpisanym argumencie daje wyniki zdefiniowane w implementacji, więc w teoria1U << i jest bardziej przenośna niż 1 << i. W praktyce wszystkie kompilatory C, jakie kiedykolwiek napotkasz, traktują podpisane lewe zmiany tak samo jak niepodpisane lewe zmiany.

Innym powodem jest to, że jeśli nSize jest niepodpisana, porównanie go ze znakiem 1 << i spowoduje wygenerowanie ostrzeżenia kompilatora. Zmiana 1 do 1U pozbywa się komunikat ostrzegawczy, i nie trzeba się martwić o to, co się dzieje, jeśli i jest 31 lub 63.

Ostrzeżenie kompilator jest najprawdopodobniej powodem 1U pojawia się w kodzie. Sugeruję skompilowanie C z włączonymi większością ostrzeżeń i usunięcie komunikatów ostrzegawczych poprzez zmianę kodu.

+1

'1 << i' nie jest zdefiniowany przez implementację. Jest dobrze zdefiniowany, o ile wartość nie przepełnia 'INT_MAX' i * niezdefiniowane zachowanie *, jeśli przepełnia się (do bitu znaku). –

+0

Przykro mi, masz rację (głównie). Jest niezdefiniowany tylko wtedy, gdy wynik nie byłby reprezentowalny w typie wyniku (standard nie wspomina o bitach znaków, ale ponieważ wszyscy używają dziś dwójki-uzupełnienie, tak się dzieje). –

5

1U jest bez podpisu. Może przenosić wartości dwa razy większe, ale bez wartości ujemnych.

W zależności od środowiska, podczas korzystania z U, mogę mieć maksymalnie 31 lub 15, nie powodując przepełnienia. Bez użycia U, i może wynosić maksymalnie 30 lub 14.

31, 30 są przeznaczone do 32 bitów Int
15, 14 są na 16-bitowe Int

+0

Ale jako stała, 1 i 1U to to samo, prawda? – arr

+0

nie. 1 to int, 1U to unsigned int. – AlexanderMP

+0

Przynajmniej w kontekście '1U << i', są one takie same, prawda? – arr

1

1U bez znaku.

Powodem, dla którego użyli wartości bez znaku w tym wyrażeniu jest (domyślam się), ponieważ nSize jest również niepodpisana, a kompilatory (po wywołaniu z określonymi parametrami) dają ostrzeżenia podczas porównywania wartości podpisanych i niepodpisanych.

Kolejny powód (mniej prawdopodobne, moim zdaniem, ale nie możemy wiedzieć bez znajomości wartości Watha nSize ma zakładać) jest to, że wartości bez znaku mogą być dwa razy większe od podpisanych, więc nSize może wynosić do ~ 4 * 10^9 zamiast ~ 2 * 10^9.

3

Jeśli nSize to int, może wynosić maksymalnie 2147483647 (2^31-1). Jeśli używasz 1 zamiast 1U następnie 1 << 30 będzie Ci 1073741824 i 1 << 31 będzie -2147483648, a więc pętla while nigdy się nie skończy, jeśli nRozmiar jest większa niż 1073741824.

Z 1U << i, 1U << 31 oceni do 2147483648, a więc możesz bezpiecznie używać go dla nSize do 2147483647. Jeśli nSize jest unsigned int, to jest również możliwe, że pętla nigdy się nie kończy, ponieważ w tym przypadku nSize może być większy niż 1U << 31.

Edit: Więc nie zgadzam się z odpowiedzi informujący nRozmiar powinny być podpisane, ale jeśli to jest podpisane, to nie powinna być ujemna ...

Powiązane problemy