2014-09-29 12 views
7

Tôi ngạc nhiên bởi hành vi của C++ khi áp dụng bit-khôn ngoan không cho một unsigned char.C++ - Bit-khôn ngoan không phải của uchar sản xuất int

Lấy giá trị nhị phân 01010101b, là 0x55 hoặc 85. Áp dụng bit-khôn ngoan không phải trên một đại diện tám bit nên sản lượng 10101010b, là 0xAA, hoặc 170.

Tuy nhiên, tôi không thể sao chép lại ở trên trong C++. Xác nhận đơn giản sau đây không thành công.

assert(static_cast<unsigned char>(0xAAu) == ~static_cast<unsigned char>(0x55u)); 

tôi in các giá trị của 0x55, 0xAA, và ~0x55 (như uchar) với đoạn mã sau. Và nó cho thấy rằng một chút khôn ngoan không làm những gì tôi mong đợi nó làm.

std::cout << "--> 0x55: " << 0x55u << ", 0xAA: " << 0xAAu << ", ~0x55: " 
    << static_cast<unsigned>(~static_cast<unsigned char>(0x55u)) << std::endl; 

--> 0x55: 85, 0xAA: 170, ~0x55: 4294967210 

Số điện thoại mà được in ra cho ~0x55 bằng 11111111111111111111111110101010b, đó là 32-bit chút khôn ngoan không của 0x55. Vì vậy, toán tử ~ đang hoạt động trên các số nguyên 32 bit ngay cả khi tôi truyền đầu vào một cách rõ ràng đến unsigned char. Tại sao vậy?

Tôi đã áp dụng một thử nghiệm khác để xem loại nhà khai thác ~ trả về loại nào. Và nó hóa ra là int trên một đầu vào unsigned char:

template <class T> 
struct Print; 

// inside main()  
Print<decltype(~static_cast<unsigned char>(0x55))> dummy; 

sản lượng các lỗi biên dịch sau đây, mà chỉ ra, rằng kết quả là loại int.

error: implicit instantiation of undefined template 'Print<int>' 
    Print<decltype(~static_cast<unsigned char>(0x55u))> dummy; 

Tôi đang làm gì sai? Hoặc, làm cách nào để có được C++ để sản xuất 0xAA từ ~0x55?

Full code đang here

Trả lời

9

chương trình khuyến mãi Integral được thực hiện trên các toán hạng của ~ chúng ta có thể thấy điều này bằng cách vào phần draft C++ standard5.3.1khai thác unary mà nói (tôi nhấn mạnh):

Toán hạng của ˜ phải có kiểu liệt kê tích phân hoặc không được điều chỉnh; kết quả là kết quả bổ sung của toán hạng. Chương trình khuyến mãi tích hợp được thực hiện. Các loại kết quả là kiểu của các toán hạng thăng chức [...]

và chương trình khuyến mãi không thể thiếu được đề cập trong phần 4.5chương trình khuyến mãi Integral và nói:

Một prvalue của một loại số nguyên khác với bool, char16_t, char32_t hoặc wchar_t có xếp hạng chuyển đổi số nguyên (4.13) nhỏ hơn xếp hạng của int có thể được chuyển đổi thành giá trị pr của loại int nếu int có thể biểu diễn tất cả các giá trị của loại nguồn ;

Để hoàn chỉnh, để thấy rằng unsigned char cấp bậc thấp hơn cấp bậc int chúng ta có thể đi đến phần 4.13Integer chuyển đổi cấp bậc mà nói:

Các hạng của một loại số nguyên đã ký phải lớn hơn xếp hạng của bất kỳ loại số nguyên đã ký nào có kích thước nhỏ hơn.

và:

Xếp hạng của char sẽ tương đương với cấp bậc của char signed và unsigned char .

Một giải pháp sẽ là gán kết quả cho unsigned char, điều này là an toàn vì bạn không phải lo lắng về tràn số nguyên đã ký.

Vì Ben Voigt chỉ ra rằng nó sẽ tuân thủ để có hệ thống ở đó sizeof (int) == 1CHAR_BIT >= 32. Trong trường hợp này, thứ hạng của unsigned char woudl không nhỏ hơn int và do đó quảng bá sẽ là int unsigned. Chúng tôi không biết bất kỳ hệ thống nào thực sự xảy ra trên đó.

+0

+1: Mặc dù nó có khả năng rõ ràng, nó là đáng nói rằng 'char' unsigned thực sự là (a) chuyển đổi thấp xếp hạng hơn 'int', và (b) đại diện đầy đủ là' int' (tất cả các giá trị 'unsigned char' có thể được biểu diễn dưới dạng' int'). Do đó, quảng cáo là âm thanh. – WhozCraig

+0

@WhozCraig đó là một yêu cầu công bằng, được thực hiện. –

+0

Cảm ơn bạn đã trả lời chi tiết! – Lemming

1

Bạn có thể loại "cắt" là 1 của hàng đầu bằng cách gán kết quả của ~0x55 một unsigned char:

#include <iostream> 

int main() 
{ 
    unsigned char input = 0x55; 
    unsigned char output = ~input; 

    std::cout << "input: " << (int)input << " output: " << (int)output << std::endl; 

    return 0; 
} 

Kết quả:

input: 85 output: 170 
+2

Không cần phải thực hiện thao tác '|', chỉ cần gán cho biến 'unsigned char' sẽ làm điều đó:' output = ~ input'. –

+0

@MarkRansom Đúng vậy! Cảm ơn. – TobiMcNamobi

2

Câu trả lời về chương trình khuyến mãi không thể thiếu là đúng.

Bạn có thể có được kết quả mong muốn bằng phương pháp đúc và Notting theo thứ tự đúng:

assert(static_cast<unsigned char>(0xAAu) == static_cast<unsigned char>(~0x55u)); 
Các vấn đề liên quan