2013-07-26 39 views
39

Tôi đã nhìn vào mã Tôi hiện đang có trong dự án của tôi và tìm thấy một cái gì đó như thế này:Tại sao ai đó sử dụng toán tử << trong khai báo enum?

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

Các << toán hạng là các toán hạng thay đổi, mà thay đổi toán hạng đầu tiên để lại bởi các bit số quy định trong toán hạng thứ hai .

Nhưng tại sao một người nào đó sử dụng điều này trong tuyên bố enum?

+21

Tôi không biết ai sẽ bỏ phiếu để đóng, nhưng đây không phải là câu hỏi "chủ yếu dựa trên ý kiến". Đó là một câu hỏi kỹ thuật hỏi cụ thể mục đích của << << 'là gì trong kịch bản này. –

+0

@GrantWinney (không phải phiếu bầu của tôi) nhưng tôi thấy nó "dựa trên ý kiến" bởi vì câu hỏi về cơ bản là "tại sao ai đó sử dụng' 1 << 2' khi '0x04' dễ đọc hơn * đối với tôi *". –

+7

Tôi chưa bao giờ nói 0x04 dễ đọc hơn và tôi cũng không so sánh cả hai. Mục đích của câu hỏi là hiểu các tác dụng phụ của câu lệnh này (= có thể kết hợp cờ) – JSBach

Trả lời

40

này cho phép bạn làm điều gì đó như thế này:

var myEnumValue = MyEnum.open | MyEnum.close; 

mà không cần phải đếm giá trị chút bội số của 2.

(như thế này):

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

** Lưu ý **: ['<<' khai báo sẽ cung cấp cho bạn tối đa là tối đa '64' trạng thái khác nhau (trên hầu hết các nền tảng). Nếu bạn cần nhiều tiểu bang có thể, giải pháp này sẽ không hoạt động] (http://stackoverflow.com/questions/8956364/app-states-with-bool-flags?answertab=votes#8956606) –

+2

Giải pháp thay thế nào sẽ cung cấp nhiều hơn 64 trạng thái trực giao? – Useless

+2

@GrijeshChauhan Hầu hết các nền tảng? Đây là C# do đó kích thước của các kiểu số nguyên không phụ thuộc vào nền tảng. Kiểu toán hạng trái cho toán tử '<<' xác định sử dụng quá tải nào. Ví dụ, với 's' một số nguyên,' 1 << s' cho một 32-bit 'int',' 1u << s' cho 32 bit không dấu 'uint',' 1L << s' cho 64-bit 'long',' 1ul << s' là 'ulong', và' (BigInteger) 1 << s' hoặc 'BigInteger.One << s' cho một số nguyên có kích thước tùy ý (yêu cầu tham chiếu đến' System.Numerics.dll 'assembly). –

22

này thường được sử dụng với bitfields, vì nó rõ ràng những gì mô hình là, loại bỏ sự cần thiết phải tự tính toán các giá trị chính xác và do đó giảm nguy cơ lỗi

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

@RichardDeeming - Dĩ nhiên là bạn cảm ơn. – Lee

+0

Tôi nghĩ rằng bạn có nghĩa là hoạt động bitwise, không bitfields. Bitfields, ít nhất trong thế giới C, là các thành phần cấu trúc con byte. – noamtm

6

Nó chỉ có nghĩa là một trình dọn dẹp/cách trực quan hơn để viết các bit. 1, 2, 3 là chuỗi có thể đọc được nhiều con người hơn 0x1, 0x2, 0x4, v.v.

10

Để tránh nhập các giá trị cho một Flags enum bằng tay.

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

+1. Người ta có thể có '[Flags]' trên 'enum' để làm rõ việc sử dụng ... nhưng không phải ai cũng quan tâm. –

6

Điều này là tạo ra một điều kiện bạn có thể kết hợp.

gì nó có hiệu quả có nghĩa đây là:

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

Đây chỉ là một phương pháp chống đạn hơn của việc tạo ra một enum [Flags].

6

Rất nhiều câu trả lời ở đây mô tả những gì cơ khí này cho phép bạn làm, nhưng không phải lý do tại sao bạn sẽ muốn sử dụng nó. Đây là lý do tại sao.

phiên bản ngắn:

ký hiệu này giúp khi tương tác với các thành phần khác và giao tiếp với các kỹ sư khác vì nó sẽ cho bạn biết một cách rõ ràng những gì bit trong một từ đang được bộ hoặc rõ ràng thay vì che khuất thông tin mà bên trong một giá trị số.

Vì vậy, tôi có thể gọi cho bạn trên điện thoại và nói "Xin chào, bạn muốn mở tệp ?" Và bạn sẽ nói, "Bit 0". Và tôi sẽ viết mã của tôi open = 1 << 0. Vì số ở bên phải của << cho bạn biết số bit.

.

phiên bản Long:

Theo truyền thống bit trong một từ được đánh số từ phải sang trái, bắt đầu từ số không. Vì vậy, bit ít quan trọng nhất là bit số 0 và bạn đếm ngược khi bạn đi về phía bit quan trọng nhất. Có một số benefits để ghi nhãn các bit theo cách này .

Một lợi ích là bạn có thể nói về cùng một bit bất kể kích thước từ. Ví dụ: tôi có thể nói rằng trong cả từ 32 bit 0x384A và từ 8 bit 0x63, các bit 6 và 1 được đặt. Nếu bạn đánh số bit theo một hướng khác, bạn không thể làm điều đó.

Một lợi ích khác là giá trị của bit chỉ đơn giản là 2 được nâng lên công suất của vị trí bit . Ví dụ: nhị phân 0101 có bit 2 và 0 được đặt. Bit 2 đóng góp giá trị 4 (2^2) vào số và bit 0 đóng góp giá trị 1 (2^0). Vì vậy, giá trị của số là tất nhiên 4 + 1 = 5.

Lời giải thích nền dài đó đưa chúng ta đến điểm: Ký hiệu << cho bạn biết số bit chỉ bằng cách nhìn vào nó.

Số 1 trong bảng sao kê 1 << n chỉ đơn giản là một bit đặt ở vị trí bit 0. Khi bạn chuyển số đó sang trái, bạn sẽ di chuyển bộ đó bit đến vị trí khác trong số. Thuận tiện, số tiền bạn thay đổi cho bạn biết số bit sẽ được đặt.

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) 

Ký hiệu này thực sự hữu ích khi bạn đang tương tác với một thành phần khác để đăng ký phần cứng. Giống như bạn có thể có thiết bị bật khi bạn viết thành bit 7. Vì vậy, kỹ sư phần cứng sẽ viết một bảng dữ liệu cho biết bit 7 cho phép thiết bị. Và bạn muốn viết trong mã của bạn ENABLE = 1 << 7. Dễ dàng như vậy.

Oh shoot. Kỹ sư vừa gửi một thông báo lỗi đến biểu dữ liệu nói rằng đó là được cho là bit 15, không chút 7. OK, chỉ cần thay đổi mã thành ENABLE = 1 << 15.

Điều gì xảy ra nếu ENABLE thực sự xảy ra khi cả hai bit 7 và 1 được đặt cùng một lúc?

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

Ban đầu có vẻ lạ và khó hiểu, nhưng bạn sẽ quen với nó. Và bạn sẽ đánh giá cao nếu bạn cần biết rõ số bit của thứ gì đó.

0

Nó bằng với sức mạnh của hai.

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

Và với enum như vậy bạn sẽ có chức năng mà trông như thế này:

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 
     } 
} 

Và gọi đến chức năng đó sẽ là foo(Enum2 | Enum3); và nó sẽ làm điều gì đó với tất cả các giá trị enum nhất định.