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?
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?
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 << 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). –
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). –
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
Ale jako stała, 1 i 1U to to samo, prawda? – arr
nie. 1 to int, 1U to unsigned int. – AlexanderMP
Przynajmniej w kontekście '1U << i', są one takie same, prawda? – arr
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.
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 ...
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). –