Czy można bezpiecznie używać -1, aby ustawić wszystkie bity na true?

Widziałem ten wzór używany wiele W C & C++.

unsigned int flags = -1;  // all bits are true
Czy to dobry przenośny sposób, aby to osiągnąć? Czy używanie 0xffffffff lub ~0 jest lepsze?
Author: Antonio, 2009-05-01

19 answers

Polecam Ci zrobić to dokładnie tak, jak pokazałeś, ponieważ jest to najbardziej prosta droga. Inicjalizuj do -1, które będzie działać zawsze , niezależnie od rzeczywistej reprezentacji znaku, podczas gdy ~ będzie czasami miało zaskakujące zachowanie, ponieważ będziesz musiał mieć odpowiedni typ operandu. Dopiero wtedy otrzymasz najwyższą wartość typu unsigned.

Dla przykładu możliwej niespodzianki, rozważ ten:

unsigned long a = ~0u;

Niekoniecznie będzie przechowywać wzorzec ze wszystkimi bitami 1 na a. Ale najpierw utworzy wzorzec ze wszystkimi bitami 1 w unsigned int, a następnie przypisze go do a. Co się dzieje, gdy unsigned long ma więcej bitów, to nie wszystkie z nich są 1.

I rozważ tę, która zawiedzie na reprezentacji dopełniacza nie-dwójki:

unsigned int a = ~0; // Should have done ~0u !

Powodem tego jest to, że ~0 musi odwrócić wszystkie bity. Odwrócenie, które da -1 na maszynie dopełniacza dwójki (która jest wartością, której potrzebujemy!), ale Nie da -1 na innej reprezentacji. Na maszynie dopełniającej jedynki daje zero. Tak więc, na maszynie dopełniacza, powyższe inicjalizuje a do zera.

Rzeczą, którą powinieneś zrozumieć jest to, że chodzi o wartości - nie o bity. Zmienna jest inicjalizowana wartością . Jeśli w inicjalizatorze zmodyfikujesz bity zmiennej używanej do inicjalizacji, wartość zostanie wygenerowana zgodnie z tymi bitami. Wartość, której potrzebujesz, aby zainicjować a do najwyższego możliwa wartość to -1 lub UINT_MAX. Drugi będzie zależał od typu a - będziesz musiał użyć ULONG_MAX dla unsigned long. Jednak pierwszy nie zależy od jego rodzaju i jest to miły sposób na uzyskanie najwyższej wartości.

Nie mówimy o tym, czy -1ma wszystkie bity jeden (nie zawsze ma). A my Nie mówimy o tym, czy ~0 ma wszystkie bity jeden (oczywiście ma).

Ale mówimy o tym, co wynikiem zainicjalizowanej zmiennej flags jest. I za to, tylko -1 będzie działać z każdym typem i maszyną.

 150
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-12 23:28:40
  • unsigned int flags = -1; jest przenośny.
  • unsigned int flags = ~0; nie jest przenośny, ponieważ polega na reprezentacji dwójki-dopełniacza.
  • unsigned int flags = 0xffffffff; nie jest przenośny, ponieważ zakłada 32-bitowe ints.

Jeśli chcesz ustawić wszystkie bity w sposób gwarantowany przez standard C, użyj pierwszego.

 43
Author: Dingo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-21 09:03:25

Szczerze mówiąc myślę, że wszystkie fff są bardziej czytelne. Jeśli chodzi o komentarz, że jego antypattern, jeśli naprawdę zależy ci na tym, że wszystkie bity są ustawione/wyczyszczone, argumentowałbym, że prawdopodobnie jesteś w sytuacji, w której zależy ci na wielkości zmiennej i tak, co wymagałoby czegoś takiego jak boost:: uint16_t, itp.

 24
Author: Doug T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 21:42:34

Sposobem na uniknięcie wspomnianych problemów jest po prostu zrobić:

unsigned int flags = 0;
flags = ~flags;
Przenośny i do rzeczy.
 17
Author: hammar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-01 13:26:28

Nie jestem pewien, czy używanie niepodpisanej liczby całkowitej dla FLAG jest dobrym pomysłem w C++. A co z bitsetem i tym podobnymi?

std::numeric_limit<unsigned int>::max() jest lepsze, ponieważ 0xffffffff zakłada, że niepodpisana liczba całkowita jest 32-bitową liczbą całkowitą.

 13
Author: Edouard A.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-10 05:26:20
unsigned int flags = -1;  // all bits are true

" czy jest to dobry [,] przenośny sposób, aby to osiągnąć?"

Przenośny? Tak . Dobrze? dyskusyjne , o czym świadczy całe zamieszanie pokazane w tym wątku. Bycie wystarczająco jasnym, aby Twoi koledzy programiści mogli zrozumieć kod bez nieporozumień, powinno być jednym z wymiarów, które mierzymy dla dobrego kodu.

Ponadto, ta metoda jest podatna na ostrzeżenia kompilatora. Aby uniknąć ostrzeżenia bez uszkadzania kompilatora, potrzebujesz wyraźnej obsady. Na przykład,

unsigned int flags = static_cast<unsigned int>(-1);

Wyraźna Obsada wymaga zwrócenia uwagi na typ celu. Jeśli zwracasz uwagę na typ celu, naturalnie unikniesz pułapek innych podejść.

Radzę zwrócić uwagę na typ celu i upewnić się, że nie ma ukrytych konwersji. Na przykład:

unsigned int flags1 = UINT_MAX;
unsigned int flags2 = ~static_cast<unsigned int>(0);
unsigned long flags3 = ULONG_MAX;
unsigned long flags4 = ~static_cast<unsigned long>(0);

Wszystkie z nich są poprawne i bardziej oczywiste dla kolegów programistów.

Oraz w C++11: możemy użyć auto, aby uczynić dowolne z nich jeszcze prostszym:

auto flags1 = UINT_MAX;
auto flags2 = ~static_cast<unsigned int>(0);
auto flags3 = ULONG_MAX;
auto flags4 = ~static_cast<unsigned long>(0);
Uważam poprawność i oczywistość za lepsze niż po prostu poprawność.
 10
Author: Adrian McCarthy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-02 12:35:52

Konwersja -1 na dowolny niepodpisany typ jest gwarantowana przez standard , aby skutkować all-ones. Użycie ~0U jest ogólnie złe, ponieważ 0 mA typ unsigned int i nie wypełni wszystkich bitów większego, niepodpisanego typu, chyba że wyraźnie napiszesz coś w rodzaju ~0ULL. W systemach sane ~0 powinny być identyczne z -1, ale ponieważ standard dopuszcza reprezentacje-dopełniacza i znaku / wielkości, ściśle mówiąc nie jest przenośny.

Oczywiście zawsze można pisać out 0xffffffff jeśli wiesz, że potrzebujesz dokładnie 32 bitów, ale -1 ma tę zaletę, że będzie działać w każdym kontekście, nawet jeśli nie znasz rozmiaru typu, np. makr, które działają na wielu typach, lub jeśli Rozmiar typu różni się w zależności od implementacji. Jeśli znasz typ, innym bezpiecznym sposobem na uzyskanie wszystkich jest makra limit UINT_MAX, ULONG_MAX, ULLONG_MAX, itd.

Osobiście zawsze używam -1. To zawsze działa i nie musisz o tym myśleć.
 9
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-01 21:02:49

Tak. Jak wspomniano w innych odpowiedziach, -1 jest najbardziej przenośny; jednak nie jest zbyt semantyczny i wyzwala ostrzeżenia kompilatora.

Aby rozwiązać te problemy, spróbuj tego prostego pomocnika:

static const struct All1s
{
    template<typename UnsignedType>
    inline operator UnsignedType(void) const
    {
        return static_cast<UnsignedType>(-1);
    }
} ALL_BITS_TRUE;

Użycie:

unsigned a = ALL_BITS_TRUE;
uint8_t  b = ALL_BITS_TRUE;
uint16_t c = ALL_BITS_TRUE;
uint32_t d = ALL_BITS_TRUE;
uint64_t e = ALL_BITS_TRUE;
 5
Author: Diamond Python,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-16 05:32:57

Tak długo, jak masz #include <limits.h> jako jeden ze swoich includes, należy po prostu użyć

unsigned int flags = UINT_MAX;

Jeśli chcesz mieć długą wartość bitów, możesz użyć

unsigned long flags = ULONG_MAX;

Te wartości gwarantują, że wszystkie bity wartości wyniku będą ustawione na 1, niezależnie od tego, w jaki sposób zaimplementowane są liczby całkowite podpisane.

 5
Author: Michael Norrish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-04 00:23:31

Nie zrobiłbym tego. Jest raczej nieintuicyjny (przynajmniej dla mnie). Przypisywanie podpisanych danych do niepodpisanej zmiennej wydaje się naruszać naturalny porządek rzeczy.

W twojej sytuacji zawsze używam 0xFFFF. (Użyj odpowiedniej liczby Fs dla zmiennej wielkości oczywiście.)

[BTW, bardzo rzadko widzę trick -1 wykonywany w kodzie realnym.]

Dodatkowo, jeśli naprawdę zależy ci na poszczególnych bitach w vairable, dobrze byłoby zacząć używać Stała szerokość uint8_t, uint16_t, uint32_t typy.

 3
Author: myron-semack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-10 05:24:21

Na procesorach Intela IA-32 można zapisać 0xFFFFFFFF do rejestru 64-bitowego i uzyskać oczekiwane wyniki. Dzieje się tak dlatego ,że IA32e (64-bitowe rozszerzenie do IA32) obsługuje tylko 32-bitowe W instrukcjach 64-bitowych 32-bitowe są znak-rozszerzone do 64-bitów.

Poniższe jest nielegalne:

mov rax, 0ffffffffffffffffh

Następujące umieszcza 64 1s w RAX:

mov rax, 0ffffffffh

Tylko dla kompletności, następujące umieszcza 32 1s w dolnej części RAX (aka EAX):

mov eax, 0ffffffffh

Oraz w rzeczywistości miałem niepowodzenie programów, gdy chciałem napisać 0xffffffffffff do zmiennej 64-bitowej i zamiast tego dostałem 0xffffffffffffffffffffff. W C będzie to:

uint64_t x;
x = UINT64_C(0xffffffff)
printf("x is %"PRIx64"\n", x);

Wynik jest następujący:

x is 0xffffffffffffffff

Pomyślałem, że wrzucę to jako komentarz do wszystkich odpowiedzi, które mówiły, że 0xFFFFFFFF zakłada 32 bity, ale tak wiele osób na to odpowiedziało, że pomyślałem, że dodam to jako oddzielną odpowiedź.

 2
Author: Nathan Fellman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-02 10:53:37

Zobacz odpowiedź litb, aby uzyskać bardzo jasne wyjaśnienie problemów.

Moja niezgoda jest taka, że, bardzo ściśle mówiąc, nie ma żadnych gwarancji dla obu przypadków. Nie znam żadnej architektury, która nie reprezentuje niepodpisanej wartości "jeden mniej niż dwa do potęgi liczby bitów", jak wszystkie bity ustawione, ale oto, co Standard faktycznie mówi (3.9.1 / 7 plus Uwaga 44):

Reprezentacje typów całkowych definiują wartości za pomocą czystej binarnej system numeracji. [Uwaga 44:] reprezentacja pozycyjna dla liczb całkowitych, która używa cyfr binarnych 0 i 1, w której wartości reprezentowane przez kolejne bity są addytywne, rozpoczynają się od 1 i są mnożone przez kolejne potęgi całkowe 2, z wyjątkiem być może dla bitu o najwyższej pozycji.

To pozostawia możliwość, że jeden z bitów będzie cokolwiek.

 2
Author: James Hopkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-12 13:41:33

Praktycznie: Tak

Teoretycznie: Nie.

-1 = 0xFFFFFFFF (lub jakikolwiek Rozmiar int jest na twojej platformie) jest prawdziwy tylko z arytmetyką dopełniacza two. W praktyce będzie działać, ale istnieją starsze maszyny tam (IBM mainframe, itp.) gdzie masz znak rzeczywisty, a nie reprezentację dopełniacza dwójki. Proponowane rozwiązanie ~0 powinno działać wszędzie.

 1
Author: Drew Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 21:41:52

Chociaż 0xFFFF (LUB 0xFFFFFFFF, itp.) może być łatwiejszy do odczytania, może złamać przenośność w kodzie, który w przeciwnym razie byłby przenośny. Rozważ na przykład procedurę biblioteczną, aby policzyć, ile elementów w strukturze danych ma ustawione określone bity(dokładne bity określone przez wywołującego). Procedura może być całkowicie agnostyczna co do tego, co reprezentują bity, ale nadal musi mieć stałą "wszystkie bity ustawione". W takim przypadku -1 będzie znacznie lepsze niż stała szesnastkowa, ponieważ będzie działać z dowolny rozmiar bitów.

Inną możliwością, jeśli dla maski bitowej używana jest wartość typedef, byłoby użycie ~(bitmaskttype)0; jeśli maska bitowa jest tylko 16-bitowym typem, to wyrażenie będzie miało ustawione tylko 16 bitów (nawet jeśli 'int' byłby 32 bitami), ale ponieważ 16 bitów będzie wszystkim, co jest wymagane, wszystko powinno być dobrze pod warunkiem, że ktoś faktycznie używa odpowiedniego typu w typecast.

Nawiasem mówiąc, wyrażenia postaci longvar &= ~[hex_constant] mają paskudną, jeśli hex stała jest zbyt duża, aby zmieścić się w int, ale zmieści się w unsigned int. Jeśli int jest 16 bitami, to longvar &= ~0x4000; lub longvar &= ~0x10000; wyczyści jeden bit longvar, ale longvar &= ~0x8000; wyczyści bit 15 i wszystkie bity powyżej tego. Wartości pasujące do int będą miały operator dopełniacza zastosowany do typu int, ale wynik będzie znak rozszerzony do long, ustawiając górne bity. Wartości, które są zbyt duże dla unsigned int, będą miały operator dopełniacza zastosowany do typu long. Wartości pomiędzy tymi rozmiarami, zastosuje jednak operator dopełniacza do typu unsigned int, który następnie zostanie przekonwertowany na typ long bez rozszerzenia znaku.

 1
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-10 16:09:34

Jak wspomnieli inni, -1 jest poprawnym sposobem tworzenia liczby całkowitej, która przekształci się w typ niepodpisany ze wszystkimi bitami ustawionymi na 1. Jednak najważniejszą rzeczą w C++ jest używanie poprawnych typów. Dlatego prawidłowa odpowiedź na twój problem (która zawiera odpowiedź na zadane pytanie) jest następująca:

std::bitset<32> const flags(-1);

To zawsze będzie zawierać dokładną ilość bitów, których potrzebujesz. Konstruuje std::bitset ze wszystkimi bitami ustawionymi na 1 z tych samych powodów wymienionych w innych odpowiedziach.

 1
Author: David Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-12 02:26:58

Jest to na pewno bezpieczne, ponieważ -1 zawsze będzie miało ustawione wszystkie dostępne bity, ale wolę ~0. -1 po prostu nie ma sensu dla unsigned int. 0xFF... nie jest dobre, ponieważ zależy od szerokości typu.

 0
Author: Zifre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-30 21:40:28

Mówię:

int x;
memset(&x, 0xFF, sizeof(int));

To zawsze daje pożądany rezultat.

 0
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-11 11:28:57

Wykorzystując fakt, że przypisanie wszystkich bitów do jednego dla typu niepodpisanego jest równoważne z pobieraniem maksymalnej możliwej wartości dla danego typu,
i rozszerzenie zakresu pytania na wszystkie unsigned typy całkowite:

Przypisanie -1 działa dla dowolnego typu unsigned integer (unsigned int, uint8_t, uint16_t, itd.) zarówno dla C jak i C++.

Jako alternatywę dla C++ możesz:

  1. Include <limits> and use std::numeric_limits< your_type >::max()
  2. W związku z tym, że typ docelowy jest typem unsigned, nie jest to typ docelowy, który może być przypisany do danego typu docelowego.]}

Celem może być dodanie większej jasności, ponieważ przypisanie -1 zawsze wymagałoby jakiegoś komentarza wyjaśniającego.

 0
Author: Antonio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:10

Tak pokazana reprezentacja jest bardzo poprawna, jak gdybyśmy zrobili to w drugą stronę, U będzie wymagało od operatora odwrócenia wszystkich bitów, ale w tym przypadku logika jest dość prosta, jeśli weźmiemy pod uwagę rozmiar liczb całkowitych w maszynie

Na przykład w większości maszyn liczba całkowita wynosi 2 bajty = 16 bitów. 2^16-1=65535 2^16=65536

0%65536=0 -1%65536=65535 co odpowiada 1111.............1 i wszystkie bity są ustawione na 1 (jeśli weźmiemy pod uwagę klasy pozostałości mod 65536) stąd jest to bardzo proste.

Chyba

No jeśli uznasz to pojęcie to jest idealnie dla niepodpisanych ints i faktycznie działa

Wystarczy sprawdzić następujący fragment programu

Int main() {

unsigned int a=2;

cout<<(unsigned int)pow(double(a),double(sizeof(a)*8));

unsigned int b=-1;

cout<<"\n"<<b;

getchar();

return 0;

}

Odpowiedź dla b = 4294967295 whcih wynosi -1% 2^32 na 4-bajtowych liczbach całkowitych

Stąd jest doskonale poprawny dla niepodpisanych liczb całkowitych

W przypadku jakichkolwiek rozbieżności raport plzz

 -6
Author: ankit sablok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-11 09:32:44