2012-07-03 36 views
12

Tôi có ba giá trị bool đại diện cho các bit. Tôi muốn có một số nguyên dưới dạngTạo một số nguyên từ ba giá trị bool dưới dạng bit trong C++

true true true = 7 
false true false = 2 

Tôi có

int val = 4*boolVal1 + 2*boolVal2 + boolVal3; 

Có một cách khác, thậm chí có đơn giản hơn?

+1

Chỉ cần fyi, không nên "đúng true" kết quả trong một 7? Nếu không, tất cả các công thức cho đến nay là sai ... – SinisterMJ

+2

'int val = 4 * boolVal1 + 2 * boolVal2 + boolVal3;' sẽ cho 7 khi bạn có đúng sự thật đúng không 8 –

+0

Đúng, tôi vừa đăng nó sai. Thx để sửa! – tzippy

Trả lời

27

Bạn có thể thấy rõ ràng hơn để sử dụng toán tử Bitwise thay vì phép nhân và ngoài:

int val = (boolVal1 << 2) | (boolVal2 << 1) | boolVal3; 
4

Khác với các phép nhân và bitshifting, bạn cũng có thể sử dụng một enum để ghi lại mối quan hệ. Thông thường không đáng để nỗ lực, nhưng chỉ để hoàn thành ...

enum Encoding 
{ 
    Flag3 = 1,  NotFlag3 = 0, 
    Flag2 = 1 << 1, NotFlag2 = 0, 
    Flag1 = 1 << 2, NotFlag1 = 0 
}; 

int val = (boolVal1 ? Flag1 : NotFlag1) | 
      (boolVal2 ? Flag2 : NotFlag2) | 
      (boolVal3 ? Flag3 : NotFlag3); 

Tại sao bạn lại bận tâm với điều này? Nó chỉ tổng quát hơn một chút, vì vậy bạn có thể thay đổi giá trị mã hóa sau này mà không phải chạm vào mã có khả năng phân phối bằng các giá trị thực (ví dụ, nếu bạn nhận ra mình đã bỏ ra một chút so với định dạng của một số tệp hoặc mạng dữ liệu bạn cần để phân tích cú pháp, bạn có thể thêm nó vào chỉ một nơi và biên dịch lại). Tất nhiên, tốt hơn hết là chỉ cung cấp một chức năng mã hóa/giải mã đơn lẻ và nếu bạn đang thêm các cờ mới, bạn vẫn cần đến nó.

Trong khi có Flag1 và NotFlag1 có vẻ vô nghĩa, thường là trường hợp bạn có thứ gì đó giống như các giá trị loại trừ lẫn nhau, hoặc Nam và Nữ, và không có lý do cụ thể nào để buộc khách hàng kiểm tra câu trả lời ! Chú ý hoặc Nữ như Nam vv ..

+0

'NotFlag's không hữu ích ở đây. Bạn vẫn sẽ kiểm tra '(giá trị & Flag2) == NotFlag2' nếu bạn muốn tìm hiểu xem Flag2 có bị xóa hay không. Bên cạnh đó, '?:' Có thể tạo mã chậm hơn so với phép nhân (phân nhánh so với phép toán số học).Ngoài ra, tôi thấy nó có ích cho các toán tử quá tải '|', '&', '^' và '~' cho các enums như vậy để loại được bảo toàn - thậm chí tôi có một macro cho nó. – krlmlr

+0

@ user946850: thường là một hàm (đặc biệt là hàm C) yêu cầu người gọi mã hóa tham số từ cờ, vì vậy mã gọi được phân phối - trong đó có thể có số lượng tùy ý và "độ sạch" của nó là rất quan trọng, có thể HOẶC cùng cờ và "NotFlag" khá vui vẻ mà không cần thử nghiệm cờ - đó là các bước được hợp nhất trong quá trình thực hiện các hàm được gọi, rất dễ bảo trì hơn. Và có, khi enums đang được sử dụng như là giá trị thích hợp trong mã khách hàng - và không chỉ cho mã hóa một nhà khai thác đúng - đúng là có giá trị. –

5

hoặc bạn có thể sử dụng phương pháp Horner:

int val = (((boolVal1 << 1) | boolVal2) << 1) | boolVal3.

này cũng làm cho nó dễ dàng hơn để thêm hoặc loại bỏ các biến từ giữa những tuyên bố mà không cần phải thay đổi tất cả các hệ số khác.

Tuy nhiên, điều này có thể ít rõ ràng hơn đối với người đọc.

+1

Không phải là vấn đề, nhưng tôi tò mò liệu - với các trình biên dịch thông thường - nó có thể tồi tệ hơn do có thứ tự tuần tự trong đánh giá: sẽ rất thú vị nếu biết/tất cả các trình tối ưu hóa của họ có thể tạo mã có thể được song song trên một đường ống dẫn CPU .... –

+0

@Tony, Bạn sẽ phải nhìn vào mã máy, nhưng tôi mong đợi các trình biên dịch hiện đại sẽ nhận thấy không có nhánh bên trong dấu ngoặc đơn và giải phóng nó khá rõ ràng. –

2

Nếu bạn biết endianness bạn cũng có thể sử dụng hành vi thực hiện xác định và bitsets, phiên bản ít về cuối nhỏ:

union foo { 
     unsigned int the_int; 
     struct { 
       unsigned int bit3:1 
       unsigned int bit2:1 
       unsigned int bit1:1 
     }; 
}; 

và sau đó cài đặt chúng:

foo.bit1 = true; 
foo.bit2 = false; 
foo.bit3 = true; 

và đọc:

foo.the_int; 

Phiên bản lớn nhất có các bit được đảo ngược và nhiều đệm (29 bit nếu)rộng 32bb) ở phía trước.

Các vấn đề liên quan