Tại sao cờ enums thường được xác định bằng các giá trị thập lục phân


122

Rất nhiều lần tôi thấy các khai báo cờ enum sử dụng các giá trị thập lục phân. Ví dụ:

[Flags]
public enum MyEnum
{
    None  = 0x0,
    Flag1 = 0x1,
    Flag2 = 0x2,
    Flag3 = 0x4,
    Flag4 = 0x8,
    Flag5 = 0x10
}

Khi tôi khai báo một enum, tôi thường khai báo nó như thế này:

[Flags]
public enum MyEnum
{
    None  = 0,
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8,
    Flag5 = 16
}

Có lý do hoặc cơ sở nào giải thích tại sao một số người chọn viết giá trị dưới dạng thập lục phân thay vì thập phân? Theo cách tôi thấy, nó dễ bị nhầm lẫn hơn khi sử dụng các giá trị hex và vô tình viết Flag5 = 0x16thay vì Flag5 = 0x10.


4
Điều gì sẽ khiến khả năng bạn viết 10ít hơn thay vì 0x10sử dụng số thập phân? Đặc biệt vì đây là các số nhị phân mà chúng ta đang xử lý, và hex có thể chuyển đổi thành / từ nhị phân một cách đáng kể? 0x111là ít gây phiền nhiễu để dịch trong đầu của một người hơn 273...
Chao

4
Thật tiếc là C # không có cú pháp không yêu cầu viết ra lũy thừa của hai.
Colonel Panic

Bạn đang làm điều gì đó vô nghĩa ở đây. Mục đích đằng sau các cờ là chúng sẽ được kết hợp theo từng bit. Nhưng các kết hợp bitwise không phải là phần tử của kiểu. Giá trị Flag1 | Flag2là 3 và 3 không tương ứng với bất kỳ giá trị miền nào của MyEnum.
Kaz

Bạn thấy điều đó ở đâu? với gương phản xạ?
giammin

@giammin Đây là một câu hỏi chung chung, không phải về cách triển khai cụ thể. Bạn có thể lấy các dự án mã nguồn mở hoặc chỉ mã có sẵn trên mạng chẳng hạn.
Adi Lester

Câu trả lời:


183

Các luận điểm có thể khác nhau, nhưng một lợi thế mà tôi thấy là hệ thập lục phân nhắc nhở bạn: "Được rồi, chúng tôi không xử lý các con số trong thế giới tùy ý do con người phát minh ra của cơ số 10 nữa. Chúng tôi đang xử lý các bit - thế giới của máy móc - và chúng tôi sẽ chơi theo luật của nó. " Hệ thập lục phân hiếm khi được sử dụng trừ khi bạn đang xử lý các chủ đề cấp tương đối thấp trong đó bố cục bộ nhớ của dữ liệu quan trọng. Sử dụng nó gợi ý thực tế rằng đó là tình huống chúng ta đang ở hiện tại.

Ngoài ra, tôi không chắc về C #, nhưng tôi biết rằng trong C x << ylà một hằng số thời gian biên dịch hợp lệ. Sử dụng dịch chuyển bit có vẻ rõ ràng nhất:

[Flags]
public enum MyEnum
{
    None  = 0,
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2,
    Flag4 = 1 << 3,
    Flag5 = 1 << 4
}

7
Điều đó rất thú vị và nó thực sự cũng là một enum C # hợp lệ.
Adi Lester

13
1 với ký hiệu này, bạn không bao giờ làm sai sót trong tính toán giá trị enum
Sergey Berezovskiy

1
@AllonGuralnek: Trình biên dịch có chỉ định vị trí bit duy nhất cho chú thích [Cờ] không? Nói chung, nó bắt đầu từ 0 và tăng lên 1, vì vậy bất kỳ giá trị enum nào được gán 3 (thập phân) sẽ là 11 ở dạng nhị phân, đặt hai bit.
Eric J.

2
@Eric: Hả, tôi không biết tại sao nhưng tôi luôn chắc chắn rằng nó đã gán giá trị lũy thừa của hai. Tôi vừa kiểm tra, và tôi đoán tôi đã nhầm.
Allon Guralnek

38
Một thực tế thú vị khác với x << yký hiệu. 1 << 10 = KB, 1 << 20 = MB, 1 << 30 = GBVà vân vân. Nó thực sự là tốt đẹp nếu bạn muốn thực hiện một mảng 16 KB cho một bộ đệm bạn chỉ có thể đivar buffer = new byte[16 << 10];
Scott Chamberlain

43

Dễ dàng nhận thấy đây là các cờ nhị phân .

None  = 0x0,  // == 00000
Flag1 = 0x1,  // == 00001
Flag2 = 0x2,  // == 00010
Flag3 = 0x4,  // == 00100
Flag4 = 0x8,  // == 01000
Flag5 = 0x10  // == 10000

Mặc dù tiến trình làm cho nó thậm chí còn rõ ràng hơn:

Flag6 = 0x20  // == 00100000
Flag7 = 0x40  // == 01000000
Flag8 = 0x80  // == 10000000

3
Tôi thực sự thêm số 0 vào trước 0x1, 0x2, 0x4, 0x8 ... Vì vậy, tôi nhận được 0x01, 0x02, 0x04, 0x08 và 0x10 ... Tôi thấy điều đó dễ đọc hơn. Tôi có đang làm rối tung thứ gì đó không?
LightStriker

4
@Light - Không hề. Nó rất phổ biến để bạn có thể thấy cách chúng sắp xếp. Chỉ cần làm cho các bit rõ ràng hơn :)
Oded

2
@LightStriker chỉ cần đi để ném nó ra khỏi đó mà không có vấn đề nếu bạn không sử dụng hex. Các giá trị chỉ bắt đầu bằng số 0 được hiểu là hệ bát phân. Trên 012thực tế cũng vậy 10.
Jonathon Reinhart

@JonathonRainhart: Điều đó tôi biết. Nhưng tôi luôn sử dụng hex khi sử dụng các trường bit. Tôi không chắc mình sẽ cảm thấy an toàn khi sử dụng int. Tôi biết điều đó thật ngu ngốc ... nhưng thói quen khó chết.
LightStriker

36

Tôi nghĩ đó chỉ là vì dãy luôn là 1,2,4,8 và sau đó thêm 0.
Như bạn có thể thấy:

0x1 = 1 
0x2 = 2
0x4 = 4
0x8 = 8
0x10 = 16
0x20 = 32
0x40 = 64
0x80 = 128
0x100 = 256
0x200 = 512
0x400 = 1024
0x800 = 2048

v.v.


13

[Flags]có nghĩa là enum thực sự là một bitfield . Với [Flags]bạn có thể sử dụng toán tử bitwise AND ( &) và OR ( |) để kết hợp các cờ. Khi xử lý các giá trị nhị phân như thế này, hầu như luôn rõ ràng hơn khi sử dụng các giá trị thập lục phân. Đây là lý do chúng tôi sử dụng hệ thập lục phân ngay từ đầu. Mỗi ký tự hex tương ứng với chính xác một nibble (bốn bit). Với số thập phân, ánh xạ 1 đến 4 này không đúng.


2
Thực ra, khả năng sử dụng các phép toán bitwise không liên quan gì đến thuộc tính flags.
Mattias Nordqvist,

4

Bởi vì có một cách cơ học, đơn giản để nhân đôi lũy thừa của hai trong hệ lục phân. Trong số thập phân, điều này là khó. Nó đòi hỏi sự nhân lên lâu dài trong đầu bạn. Trong hex, đó là một thay đổi đơn giản. Bạn có thể thực hiện điều này theo mọi cách 1UL << 63mà bạn không thể thực hiện trong hệ thập phân.


1
Tôi nghĩ điều này có ý nghĩa nhất. Đối với các enum có tập hợp giá trị lớn, đó là cách dễ dàng nhất (trừ trường hợp có thể có ví dụ của @ Hypercube).
Adi Lester

3

Bởi vì nó dễ dàng hơn để theo dõi đối với con người nơi các bit trong cờ. Mỗi chữ số thập lục phân có thể phù hợp với một nhị phân 4 bit.

0x0 = 0000
0x1 = 0001
0x2 = 0010
0x3 = 0011

... and so on

0xF = 1111

Thông thường, bạn muốn cờ của mình không chồng chéo các bit, cách dễ nhất để thực hiện và hình dung nó là sử dụng các giá trị thập lục phân để khai báo cờ của bạn.

Vì vậy, nếu bạn cần cờ có 16 bit, bạn sẽ sử dụng các giá trị thập lục phân 4 chữ số và bằng cách đó, bạn có thể tránh các giá trị sai:

0x0001 //= 1 = 000000000000 0001
0x0002 //= 2 = 000000000000 0010
0x0004 //= 4 = 000000000000 0100
0x0008 //= 8 = 000000000000 1000
...
0x0010 //= 16 = 0000 0000 0001 0000
0x0020 //= 32 = 0000 0000 0010 0000
...
0x8000 //= 32768 = 1000 0000 0000 0000

Cách giải thích này là tốt .... chỉ điều thiếu là tương đương với nhị phân để hiển thị các dòng cuối cùng lên của các bit, Nibbles, và byte;)
GoldBishop
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.