2009-11-17 31 views
20

Tôi có một giá trị như thế này:giải thích ký như unsigned

int64_t s_val = SOME_SIGNED_VALUE; 

Làm thế nào tôi có thể nhận được một

uint64_t u_val 

đó có chính xác các mẫu bit giống như s_val, nhưng được coi là unsigned?

Điều này có thể thực sự đơn giản, nhưng sau khi xem trên Stackoverflow và các nơi khác tôi chưa bật câu trả lời.

+0

Tăng phiếu bầu cho tất cả mọi người; Cảm ơn vì đầu vào của bạn. Tôi nghĩ rằng static_cast là trong thực tế, câu trả lời đúng. Đối với các hồ sơ, tôi đã thử nó đầu tiên, nhưng do một lỗi dunderheaded ở nơi khác tôi nghĩ rằng nó đã không được bảo quản các mẫu bit. Để làm rõ câu hỏi, không sao là s_val! = U_val (sẽ là trường hợp nếu s_val <0). Các bit là những gì quan trọng. – bbg

Trả lời

28
int64_t s_val = SOME_SIGNED_VALUE; 
uint64_t u_val = static_cast<uint64_t>(s_val); 

C++ chuẩn 4.7/2 tiểu bang rằng:

Nếu loại đích là unsigned, giá trị kết quả là số nguyên unsigned nhất đồng dư với số nguyên nguồn (modulo 2 n trong đó n là số lượng bit được sử dụng để đại diện cho loại không dấu). [Lưu ý: Trong biểu diễn bổ sung của hai, chuyển đổi này là khái niệm và không có thay đổi trong mẫu bit (nếu không có cắt ngắn). ]

Từ Mặt khác, Standard nói rằng "Các bản đồ được thực hiện bởi reinterpret_cast là thực hiện xác định [Ghi chú:.. Nó có thể hoặc có thể không, tạo ra một đại diện khác với giá trị ban đầu]" (5.2. 10/3). Vì vậy, tôi khuyên bạn nên sử dụng static_cast.

2

Bạn cũng có thể reinterpret_cast nó, hoặc sử dụng một union:

union { 
    int64_t i64; 
    uint64_t ui64; 
} variable; 

variable.i64 = SOME_SIGNED_VALUE; 
uint64_t a_copy = variable.ui64; 
+1

'static_cast' sẽ không dẫn đến mất mẫu bit. –

+0

không. Tôi tự hỏi tại sao không ... – xtofl

+1

Tôi hơi lo lắng về static_cast <>. Tôi cũng sẽ đề nghị sử dụng reinterpret_cast <> bởi vì câu lệnh mẫu bit. Bạn có chắc chắn static_cast <> sẽ làm việc (tôi nghĩ rằng nó sẽ nhưng không có một bản sao của tiêu chuẩn tiện dụng). Nhưng reinterpret_cast <> cũng là một dấu hiệu cho biết đó là một diễn viên không an toàn. –

6

Nói chung, nó không quan trọng cho dù bạn sử dụng static_cast<int64_t> hoặc reinterpret_cast<int64_t>. Vì vậy, miễn là bạn đang chạy trên một bộ xử lý sử dụng two's complement để đại diện cho số âm, kết quả là như nhau. (Thực tế tất cả các bộ xử lý hiện đại đều sử dụng nó.) Dưới sự bổ sung của hai, một số dương trong một int đã ký được biểu diễn theo cách tương tự trong một int không dấu; nếu đó là một số âm, nó sẽ được diễn giải lại thành một số dương lớn ở dạng chưa ký.

Về cơ bản, những gì diễn viên của bạn làm là yêu cầu trình biên dịch tạo ra các hướng dẫn lắp ráp khác nhau khi xử lý với giá trị đó. Ví dụ. có các hướng dẫn khác nhau về nhân và chia cho các số nguyên đã ký. Mặc dù cộng và trừ vẫn giữ nguyên (đọc liên kết wikipedia và bạn sẽ hiểu).

+0

Nhưng còn giá trị âm thì sao? –

+0

Quy tắc là "nếu loại mới chưa được ký, giá trị được chuyển đổi bằng cách liên tục cộng hoặc trừ nhiều hơn giá trị lớn nhất có thể được thể hiện trong loại mới cho đến khi giá trị nằm trong phạm vi của loại mới", hoạt động cho sự bổ sung của 2, và tôi nghĩ rằng bổ sung 1, nhưng tôi sẽ không thề rằng nó giữ cùng một mô hình bit cho biểu diễn bizzaro nhiều số âm. –

+0

Ở trên là từ tiêu chuẩn C99, tiêu chuẩn C++ nói điều này: "giá trị kết quả là số nguyên ít nhất chưa được gán cho số nguyên nguồn (modulo 2n trong đó n là số bit được sử dụng để biểu diễn loại không dấu). Trong biểu diễn bổ sung của hai, chuyển đổi này là khái niệm và không có thay đổi trong mẫu bit (nếu không có cắt bớt).] " –

5

Mẫu bit logic (bit đại diện giá trị), nghĩa là giá trị của chữ số nhị phân chỉ có thể được giữ nguyên nếu giá trị đã ký ban đầu không âm, vì giá trị âm không thể được biểu thị bằng biến số nguyên không dấu. Tất cả những gì bạn cần làm là gán giá trị đã ký cho đối tượng tích phân chưa được ký của mình và bạn đã hoàn thành

uint64_t u_val = s_val; 

Không sử dụng diễn xuất rõ ràng, nhưng có thể được sử dụng để ngăn chặn cảnh báo trình biên dịch.

Đối với mẫu bit vật lý (tức là những gì bạn nhìn thấy trong bộ nhớ thô, bit của biểu diễn đối tượng), bạn chỉ đơn giản là không thể "chuyển đổi" theo cách đó. Ngôn ngữ C++ không cung cấp cho bạn bất kỳ phương thức chuyển đổi nào đảm bảo bảo toàn mẫu bit vật lý.Tất cả các bạn có thể làm là diễn giải lại bộ nhớ bị chiếm đóng bởi các đối tượng ký kết như một đối tượng unsigned của cùng một kích thước

STATIC_ASSERT(sizeof(int64_t) == sizeof(uint64_t)); 
uint64_t u_val = reinterpret_cast<uint64_t&>(s_val); 

Một lần nữa, đây không phải là một chuyển đổi, mà là một lối trình diễn bộ nhớ. Điều này không được bảo đảm để làm việc và điều này nói chung là bất hợp pháp.

+0

Điểm tốt để phân biệt "chuyển đổi" từ "diễn giải"! – xtofl

+0

Làm thế nào là bất hợp pháp? Bạn có ý nghĩa gì bởi 'công việc'? Bạn _can_ 'reinterpret' trở lại, phải không? – xtofl

+0

Nó là bất hợp pháp becuse C++ ngôn ngữ explcitly cấm truy cập bộ nhớ bị chiếm đóng bởi một đối tượng của loại 'T' như là một đối tượng của loại khác nhau' U' (với vài trường hợp ngoại lệ). Nói cách khác, đọc bộ nhớ tái diễn là hầu như bất hợp pháp. – AnT

10

Lưu ý rằng bạn không cần sử dụng dàn diễn viên nào cả. Đối với tất cả các cuộc tranh cãi về việc liệu các diễn viên sẽ munge bit hay không cho đại diện tiêu cực, một điều đã bị lạc - diễn viên là hoàn toàn không cần thiết.

Do chuyển đổi C/C++ sẽ làm (và làm thế nào đúc được định nghĩa), điều này:

int64_t s_val = SOME_SIGNED_VALUE; 
uint64_t u_val = s_val; 

là chính xác tương đương với:

int64_t s_val = SOME_SIGNED_VALUE; 
uint64_t u_val = static_cast<uint64_t>(s_val); 

Điều đó nói rằng, bạn có thể vẫn muốn các diễn viên vì nó tín hiệu ý định. Tuy nhiên, tôi đã nghe nó lập luận rằng bạn không nên sử dụng phôi không cần thiết bởi vì nó có thể im lặng trình biên dịch trong các tình huống mà bạn có thể muốn một cảnh báo.

Chọn chất độc của bạn.

+1

Aha, đó là một điểm tốt. Trong trường hợp của tôi, tôi nghĩ rằng đó là cách tốt nhất để báo hiệu ý định, nhưng tôi rất vui khi thấy cảnh báo trước. – bbg

5

Tôi đồng ý static_cast là thích hợp trong trường hợp này, nhưng không ai đề cập đến trường hợp tìm kiếm rất giống nhau nơi static_cast sẽ không giữ lại các bit như mong đợi.

char x = -1; // 255 
unsigned int x2 = static_cast<unsigned int>(x); // 4294967295 
unsigned int x3 = static_cast<unsigned int>(static_cast<unsigned char>(x)); // 255 

Xem ra cho sign extension khi bạn truyền từ một giá trị đã ký nhỏ sang giá trị chưa ký lớn. Có thể các kết hợp khác cũng dễ bị tổn thương - tôi chưa từng nghĩ hết.

+0

Điểm thú vị; cảm ơn vì đã giải thích và cung cấp liên kết để ký gia hạn. – bbg

1

Muốn chia sẻ giải pháp chung hiện đại, C++ 14 này. Ban đầu được chứng minh here.

template<class T> 
auto as_unsigned(T t) 
{ 
    return std::make_unsigned_t<T>(t); 
} 

Trong đó có thể được sử dụng như sau:

auto sx = int32_t{ 55 }; 
auto ux = as_unsigned(sx); 

Bạn có thể nhìn thấy nó trong hành động here.