2011-09-26 32 views
5

Chúng tôi đã tìm thấy một số giá trị lạ được tạo ra, một trường hợp thử nghiệm nhỏ bên dưới. Bản in này "FFFFFFFFF9A64C2A". Có nghĩa là unsigned dài dài dường như đã được ký mở rộng. Nhưng tại sao? Tất cả các loại dưới đây đều chưa được ký, vì vậy tiện ích mở rộng ký hiệu là gì? Đầu ra dự kiến ​​ sẽ là "F9A64C2A".Tiện ích mở rộng ký hiệu có ký hiệu dài

#include <stdio.h> 

int main(int argc,char *argv[]) 
{ 
    unsigned char a[] = {42,76,166,249}; 

    unsigned long long ts; 
    ts = a[0] | a[1] << 8U | a[2] << 16U | a[3] << 24U; 

    printf("%llX\n",ts); 


    return 0; 

} 

Trả lời

5

Trong biểu a[3] << 24U, các a[1] có kiểu unsigned char. Bây giờ, "xúc tiến integer" chuyển đổi nó để int vì:

Sau đây có thể được sử dụng trong một biểu hiện bất cứ nơi nào một int hay unsigned int thể được sử dụng:

[...]

Nếu int có thể đại diện cho tất cả các giá trị của loại ban đầu, giá trị được chuyển đổi thành an int; nếu không, nó được chuyển đổi thành unsigned int.

((draft) ISO/IEC 9899:1999, 6.3.1.1 2)

Xin lưu ý rằng các nhà khai thác cũng thay đổi (trừ hầu hết các nhà khai thác khác) làm không làm "chuyển đổi số học bình thường" chuyển đổi cả hai toán hạng để một loại phổ biến . Nhưng

Loại kết quả là toán hạng bên trái được quảng bá.

(6.5.7 3)

Trên một nền tảng 32 bit, 249 << 24 = 4177526784 hiểu là một int đã thiết lập dấu bit của nó.

Chỉ cần thay đổi để

ts = a[0] | a[1] << 8 | a[2] << 16 | (unsigned)a[3] << 24; 

sửa chữa các vấn đề (Hậu tố U cho hằng số không có tác động).

+0

Chỉnh sửa nhỏ: 'a [1]' có loại 'unsigned char'. –

+0

@ user964970: Đọc lại. Kiểu 'x << y' không liên quan gì đến kiểu' y'. –

+0

@Dietrich Epp: Cảm ơn bạn. –

1
 
ts = ((unsigned long long)a[0]) | 
    ((unsigned long long)a[1] << 8U) | 
    ((unsigned long long)a[2] << 16U) | 
    ((unsigned long long)a[3] << 24U); 

Đúc ngăn chặn chuyển đổi kết quả trung gian để loại mặc định int.

+1

Nhưng * tại sao * có kết quả int trung gian, khi tất cả các loại có liên quan là các loại chưa ký? Thủ phạm dường như chỉ là 'a [0] 'đầu tiên, thay thế bằng' (unsigned) a [0] 'là tất cả. Nhưng tại sao. – user964970

1

Một số dịch chuyển [i], khi được tự động chuyển đổi từ unsigned char thành int, tạo ra các giá trị được ký dài.

Điều này phù hợp với mục 6.3.1 Toán hạng số học, phần con 6.3.1.1 Boolean, ký tự và số nguyên, của C dự thảo tiêu chuẩn N1570, đọc một phần, "2. Có thể sử dụng sau đây trong biểu thức bất cứ nơi nào int hoặc unsigned int có thể được sử dụng: ... - Một đối tượng hoặc biểu thức với một số nguyên (khác int hoặc unsigned int) có xếp hạng chuyển đổi số nguyên nhỏ hơn hoặc bằng với thứ hạng int và unsigned int. .. Nếu một int có thể đại diện cho tất cả các giá trị của kiểu ban đầu ..., giá trị được chuyển đổi thành một int, nếu không, nó được chuyển đổi thành một int không dấu .. Đây được gọi là các chương trình khuyến mãi số nguyên. giữ lại giá trị bao gồm cả dấu hiệu. "

Xem ví dụ www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf

Bạn có thể sử dụng mã như sau, trong đó hoạt động ok:

 int i; 
     for (i=3, ts=0; i>=0; --i) ts = (ts<<8) | a[i]; 
+0

Tất cả các [i] được dịch chuyển, trong mã ví dụ, có mặt bên phải là chưa ký do tiền tố U trên hằng số. (ví dụ: << 8U), có nghĩa là ví dụ: biểu thức a [1] << 8U phải có loại chưa ký, theo các quy tắc đó. – user964970

+0

@ user964970: Thủ phạm không phải là 'a [0]'. Tuy nhiên, việc đúc 'a [0]' thành 'unsigned' sẽ buộc kết quả của bitwise hoặc là' unsigned', mà cắt ngắn phần mở rộng dấu xuất hiện trong 'a [3] << 24', là thủ phạm thực sự. –

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