2013-07-26 14 views
39

Szukałem w kodzie mam aktualnie w moim projekcie i znalazłem coś takiego:Dlaczego ktoś użyłby operatora << w deklaracji wyliczeniowej?

public enum MyEnum 
{ 
    open  = 1 << 00, 
    close = 1 << 01, 
    Maybe = 1 << 02, 
    ........ 
} 

<< argument jest operand shift, który przesuwa pierwszy operand lewo przez bity liczby określonej w drugim argumencie .

Ale dlaczego ktoś użyłby tego w deklaracji enum?

+21

Nie wiem, kto głosuje, aby to zamknąć, ale nie jest to pytanie "oparte głównie na opiniach". Jest to techniczne pytanie, zadające konkretnie, jaki jest cel "<<" w tym scenariuszu. –

+0

@GrantWinney (nie moje krótkie głosy), ale widzę, jak to jest "oparte na opiniach", ponieważ pytanie jest zasadniczo "dlaczego ktoś używa' 1 << 2', gdy '0x04' jest bardziej czytelny * dla mnie *". –

+7

Nigdy nie powiedziałem, że 0x04 jest bardziej czytelny i nie porównałem obu. Intencją pytania jest zrozumienie skutków ubocznych tego stwierdzenia (= możliwość łączenia flag) – JSBach

Odpowiedz

40

To pozwala zrobić coś takiego:

var myEnumValue = MyEnum.open | MyEnum.close; 

bez konieczności liczenia wartości bitowe wielokrotność 2.

(jak ten):

public enum MyEnum 
{ 
    open  = 1, 
    close = 2, 
    Maybe = 4, 
    ........ 
} 
+1

** Uwaga **: Deklaracja "<< << da ci maksymalnie 64 różne stany (na większości platform). Jeśli potrzebujesz więcej możliwych stanów, to rozwiązanie nie będzie działać] (http://stackoverflow.com/questions/8956364/app-states-with-bool-flags?answertab=votes#8956606) –

+2

Jakie alternatywne rozwiązanie da więcej niż 64 stany ortogonalne? – Useless

+2

@GrijeshChauhan Większość platform? To jest C#, więc rozmiar typów całkowitych nie zależy od platformy. Typ lewego operandu do operatora '<<' określa, którego przeciążenia użyć. Na przykład, gdy 's' jest liczbą całkowitą,' 1 << s' daje 32-bitowe 'int',' 1u << s' daje 32-bitowe unsigned 'uint',' 1L << s' daje 64-bitowe 'long',' 1ul << s' to 'ulong', a' (BigInteger) 1 << s' lub 'BigInteger.One << s' daje dowolnie wybraną liczbę całkowitą (wymaga odwołania do' System.Numerics.dll 'montaż). –

22

ten jest zwykle stosowany z bitfields, ponieważ jest jasne, jaki wzór jest, usuwa konieczność ręcznego obliczania prawidłowych wartości, a tym samym zmniejsza ryzyko błędów

[Flags] 
public enum SomeBitField 
{ 
    open = 1 << 0 //1 
    closed = 1 << 1 //2 
    maybe = 1 << 2 //4 
    other = 1 << 3 //8 
    ... 
} 
+1

@RichardDeeming - Masz rację, oczywiście, dzięki. – Lee

+0

Myślę, że masz na myśli operacje bitowe, a nie bitfields. Bitfieldy, przynajmniej w świecie C, są sub-bajtowymi członkami struktury. – noamtm

6

To właśnie ma być czystsze/bardziej intuicyjny sposób pisania bitów. 1, 2, 3 to bardziej czytelna dla człowieka sekwencja niż 0x1, 0x2, 0x4 itd.

10

Aby uniknąć ręcznego wyliczania wartości dla enum Flags.

public enum MyEnum 
{ 
    open  = 0x01, 
    close = 0x02, 
    Maybe = 0x04, 
    ........ 
} 
+5

+1. Ktoś prawdopodobnie użyłby '[Flags]' na takiej 'enum', aby wyjaśnić użycie ... ale nie wszyscy się tym przejmują. –

6

To jest wyliczenie, które można łączyć.

Co to w rzeczywistości oznacza to:

public enum MyEnum 
{ 
    open = 1; 
    close = 2; 
    Maybe = 4; 
    //... 
} 

To jest po prostu bardziej kuloodporne metoda tworzenia [Flags] enum.

6

Wiele odpowiedzi tutaj opisujące, co ta mechanika pozwala ci zrobić, ale nie dlaczego chcesz z niej skorzystać. Dlatego.

Krótka wersja:

Taki zapis pomaga podczas interakcji z innymi komponentami i komunikuje z innymi inżynierami, ponieważ mówi jawnie co nieco w słowie jest bycie zestaw lub jasne zamiast przesłaniając te informacje Wewnątrz wartość numeryczna.

Mogę do ciebie zadzwonić i powiedzieć "Hej, co to jest za otwarcie pliku ?" A ty powiedziałbyś "Bit 0". I napisałbym w moim kodzie open = 1 << 0. Ponieważ numer po prawej stronie << informuje o numerze bitu.

.

Długa wersja:

Tradycyjnie bitów w słowie są numerowane od prawej do lewej, zaczynając od zera. Najmniej znaczącym bitem jest bit numer 0, a liczony jako najbardziej znaczący bit liczony jest w kierunku . Istnieje kilka benefits do oznaczania bitów w ten sposób .

Jedną z korzyści jest to, że można mówić o tym samym bicie niezależnie od rozmiaru słowa. Np. Mógłbym powiedzieć, że zarówno 32-bitowe słowo 0x384A, jak i 8-bitowe słowo 0x63, są ustawione bity 6 i 1. Jeśli policzyłeś swoje bity w przeciwnym kierunku, nie możesz tego zrobić.

Inną korzyścią jest to, że wartość bitu to po prostu 2 podniesione do potęgi pozycji bitowej . Na przykład binarny 0101 ma ustawione bity 2 i 0. Bit 2 ma wartość , a bit 0 ma wartość 1 (2^0). Tak więc wartość liczbowa wynosi oczywiście 4 + 1 = 5.

To długowieczne wyjaśnienie tła doprowadza nas do punktu: notacja << podaje numer bitu, po prostu patrząc na niego.

numer 1 samodzielnie w sprawozdaniu 1 << n jest tylko jeden bit ustawiony w pozycji bit 0. Gdy przesunięcie że liczba lewo, jesteś w ruchu, które następnie ustawić trochę na innej pozycji w liczbie. Dogodnie, liczba przesunięć informuje o numerze bitu, który zostanie ustawiony.

1 << 5: This means bit 5. The value is 0x20. 
1 << 12: This means bit 12. The value is 0x40000. 
1 << 17: This means bit 17. The value is 0x1000000. 
1 << 54: This means bit 54. The value is 0x40000000000000. 
      (You can probably see that this notation might be helpful if 
      you're defining bits in a 64-bit number) 

Ten zapis naprawdę przydaje się, gdy jesteś interakcji z innym komponentem , jak odwzorowywanie bitów w słowie do rejestru sprzętowego. Podobnie jak Ty możesz mieć urządzenie, które włącza się podczas pisania na bit 7. Inżynier sprzętu napisałby arkusz danych, który mówi, że bit 7 włącza urządzenie. A ty napiszesz w swój kod ENABLE = 1 << 7. To proste.

Och strzelać. Inżynier właśnie wysłał erratę do arkusza informacyjnego, mówiąc, że jest to bit 15, a nie bit 7. To jest OK, wystarczy zmienić kod na ENABLE = 1 << 15.

Co jeśli ENABLE było rzeczywiście, gdy oba bity 7 i 1 zostały ustawione w tym samym czasie?

ENABLE = (1 << 7) | (1 << 1).

Z początku może wyglądać dziwnie i tępo, ale przyzwyczaisz się do tego. I będziesz wdzięczny za to, jeśli kiedykolwiek wyraźnie będziesz potrzebował znać numer bitowy czegoś.

0

Jest to równa mocy dwóch.

public enum SomeEnum 
{ 
    Enum1 = 1 << 0, //1 
    Enum2 = 1 << 1, //2 
    Enum3 = 1 << 2, //4 
    Enum4 = 1 << 3  //8 
} 

iz taką wyliczenia trzeba będzie funkcję, która wygląda tak:

void foo(unsigned ind flags) 
{ 
    for (int = 0; i < MAX_NUMS; i++) 
     if (1 << i & flags) 
     { 
      //do some stuff... 
      //parameter to that stuff probably is i either enum value 
     } 
} 

I zadzwonić do tej funkcji byłoby foo(Enum2 | Enum3); i będzie coś zrobić z wszystkich podanych wartości enum.

Powiązane problemy