2011-02-07 35 views
5

Tôi hiểu rằng có thể sử dụng bitmask trong các giá trị enum, nhưng tôi không biết cách tạo nó.Kết hợp Giá trị Enum bằng Bitmask

Tôi có một enum đơn giản:

enum State 
{ 
    minimizing = 0, 
    maximizing, 

    minimized, 
    maximized 
}; 

Một trạng thái luôn luôn là State.minimized hoặc State.maximized, và có thể có nhà nước bổ sung đã đổi kích thước. Vì vậy, một cái gì đó có thể được tối đa hóa và giảm thiểu

Trả lời

16

Tôi sẽ giả định rằng myState có loại enum State của bạn.

Việc sử dụng truyền thống của enum là tạo các giá trị không đổi mà một biến loại này có thể thực hiện. Bạn muốn đặt biến số myState thành số kết hợp của các giá trị được xác định trong enum.

enum xác định 1, 2, 4 và 8 làm giá trị hợp lệ, nhưng bạn muốn có thể đặt biến thành 4 | 2 = 6. Trong khi C sử dụng loại int được triển khai của bạn cho tất cả enum, nó không phải là trường hợp trong C++. myState = 6 không hợp lệ trong C++. Trên thực tế, myState = 4 không hợp lệ trong C++, bạn cần truyền một cách rõ ràng hoặc sử dụng một trong các tên không đổi của enum.

Mặc dù có thể trong C, thực hành không tốt là đặt myState thành giá trị không được xác định theo loại của nó (ví dụ đến 6).

Trong trường hợp của bạn, một giải pháp mà dường như hậu quả sẽ là:

typedef enum { 
    OTHER, 
    MINIMIZED, 
    MAXIMIZED 
} win_size_t; 

typedef struct { 
    win_size_t current; 
    win_size_t next; 
} state_t; 

state_t myState; 

Bằng cách đó, bạn có thể viết thư cho các lĩnh vực currentnext undependently.

Nếu bạn vẫn muốn có các trường bit, bạn có thể đặt kích thước của các phần tử của cấu trúc theo bit. Nó là loại nguy hiểm mặc dù, việc thực hiện các lĩnh vực bit phụ thuộc vào trình biên dịch của bạn. Tôi thậm chí không chắc chắn nếu trình biên dịch sẽ chấp nhận để có một loại enum trong một lĩnh vực bit (nên được ok trong C, kể từ enum s là int).

typedef struct { 
    win_size_t current : 2; // not tested 
    win_size_t next : 2; 
} state_t; 

Các giải pháp đã cho trước đó là hợp lệ.Quan điểm của tôi là nếu biến số myState của bạn có loại enum State, nó chỉ nên sử dụng các thành viên của enum cho các giá trị của nó, không phải kết hợp.

Có thể myState có loại khác, tôi biết điều gì.


Nếu myState không phải là loại enum State, sau đó bạn có thể sử dụng các hằng số được định nghĩa trong enum của bạn kết hợp.

enum State { 
    MINIMIZING = (1u << 0), 
    MAXIMIZING = (1u << 1), 
    MINIMIZED = (1u << 2), 
    MAXIMIZED = (1u << 3), 
}; 

unsigned int myState = 0; 

myState |= MAXIMIZED; // sets that bit 
myState &= ~MAXIMIZED; // resets that bit 

này cho phép bạn làm hai việc trong một công việc:

myState = MAXIMIZED | MINIMIZING; 

Nhưng cũng có những thứ bạn không có khả năng muốn:

myState = MAXIMIZED | MINIMIZED; // does that make sense? 
+0

cảm ơn! Tôi đã đi cho tùy chọn # 1. Thật vậy mà không có cảm giác rằng 'MAXIMIZED | MINIMIZED' là có thể, và cho nó tốt hơn cho khả năng đọc để có hai enums. –

+0

Xin lưu ý rằng việc hạn chế liệt kê các bit được đệ trình là hành vi không xác định và kết quả phụ thuộc vào trình biên dịch. Ngoài ra xin vui lòng sửa tôi Nếu tôi sai. –

+0

@ DavidTóth Bạn có vẻ đúng, cảm ơn vì điều này! https://stackoverflow.com/a/33590935/108802 – Gauthier

2

Bạn có thể nhận được hiệu ứng này bằng cách chỉ định tất cả các trường trong enum và tăng quyền hạn của hai để có được hiệu ứng bitmask. Ví dụ: trong trường hợp của bạn:

enum State 
{ 
    minimizing = 1, 
    maximizing = 2, 

    minimized = 4, 
    maximized = 8 
}; 

Vì vậy, bạn có thể có kết hợp (State.maximized | State.minimizing). Tuy nhiên, điều này sẽ không áp dụng giới hạn chỉ là State.maximized hoặc State.minimized. Nếu bạn muốn làm điều đó bạn có thể chuyển đổi chúng thành một bit duy nhất, nhưng tôi tưởng tượng trong ví dụ này bạn sẽ muốn có thể có một trường hợp không được tối đa hóa hoặc giảm thiểu.

+2

thường được viết bằng ca làm việc – justin

+0

nhưng sau đó, làm cách nào tôi có thể sử dụng? Giống như tôi có: 'myState = minimized; if (isMaximizing) {myState = maximizing} 'Tôi muốn thiết lập trạng thái tối đa, mà không mất trạng thái thu nhỏ –

+0

Sau đó, bạn có thể sử dụng' myState | = maximizing; '. Điều này đặt bit bạn thú vị mà không cần chạm vào các bit khác. Đối với zeroing, sử dụng 'myState & = ~ maximumimizing;'. Hãy cẩn thận khi so sánh, 'myState == minimized' sẽ không hoạt động, bạn cần' (myState & minimized) == minimized' (hoặc '! = 0'). Nếu tôi là bạn, tôi sẽ xem xét một cấu trúc với một trường là "trạng thái hiện tại" và một trường khác cho "trạng thái tiếp theo". – Gauthier

12

Sử dụng một chút khác nhau cho mỗi giá trị trong liệt kê của bạn, chẳng hạn như:

enum State 
{ 
    minimizing = 0x01, // 00000001 
    maximizing = 0x02, // 00000010 
    minimized = 0x04, // 00000100 
    maximized = 0x08 // 00001000 
}: 

Sau đó, bạn có thể kết hợp nhiều giá trị với Bitwise hoặc (minimizing | maximized) và thử nghiệm cho các giá trị với Bitwise và (bool is_minimized = (flags & minimized);).

+2

Câu hỏi về hương vị, nhưng tôi thích: '(1u << 0)', '(1u << 1)', '(1u << 2)', '(1u << 3)'. Nó là rõ ràng hơn mà bạn có nghĩa là bit. – Gauthier

+0

Tại sao xác định các giá trị trong ký hiệu hex? 'minimizing = 1' hoạt động quá –

+4

@NatanYellin: có, nhưng nếu bạn muốn thêm một trạng thái nữa và bạn đang sử dụng số thập phân, bạn phải viết 16. Giả sử bạn muốn đặt hai bit, bit 4 và bit 1. Kết quả là 18 thập phân, ít đọc hơn 0x12 (nếu điều này không rõ ràng, hãy thử xác định bit nào được đặt trong thập phân 2398. Dễ dàng hơn nhiều nếu bạn có 0x95E tương đương). Nếu bạn quan tâm đến bit nào được thiết lập, hệ thập lục phân là cách để đi. – Gauthier

2

Tôi chỉ cố gắng này trong VS2012, các Trình tối ưu hóa dường như kết hợp chính xác các bit mà không cần hỗ trợ nếu bạn đang sử dụng bitfields.

struct BITS { int x: 1; int y:1; }; 

sau đó

BITS b; 
b.x = b.y = 1; 

Sets cả hai bit với một hướng dẫn.