2012-07-03 31 views
17

Loại mặc định của hằng số nguyên được ký hoặc chưa ký? chẳng hạn như 0x80000000, làm cách nào tôi có thể quyết định sử dụng nó dưới dạng hằng số nguyên đã ký hoặc hằng số nguyên không dấu mà không có bất kỳ hậu tố nào?Kiểu mặc định của hằng số nguyên được ký hoặc chưa ký?

Nếu đó là hằng số nguyên đã ký, cách giải thích trường hợp sau?

printf("0x80000000>>3 : %x\n", 0x80000000>>3); 

đầu ra:

0x80000000>>3 : 10000000 

Các trường hợp dưới đây có thể cho thấy nền tảng của tôi sử dụng dịch chuyển bitwise số học, không lôgic Bitwise thay đổi:

int n = 0x80000000; 

printf("n>>3: %x\n", n>>3); 

đầu ra:

n>>3: f0000000 
+1

Thông thường, '0x80000000' là' INT_MAX + 1', vì vậy nó chưa được ký. Do đó thay đổi logic trong ví dụ đầu tiên. Nhưng khi bạn gán nó vào một 'int', bạn gọi hành vi không xác định, và thường kết quả là' INT_MIN'. Các số nguyên âm chuyển dịch trái được thực hiện, thường sử dụng phép dịch số học. Sự khác biệt là ở phần sau, bạn buộc nó vào một loại đã ký. –

+0

@DanielFischer 'INT_MAX + 1' là UB nhưng' int n = 0x80000000; 'không phải là UB nhưng được thực hiện xác định và chuyển đổi số nguyên trong trường hợp này được cai trị bởi 6.3.1.3p3 (trong C99) – ouah

+0

@ouah The' INT_MAX + 1' có nghĩa là biểu thức toán học, chứ không phải C.Tuy nhiên, chính xác là việc chuyển đổi thành 'int' không phải là hành vi không xác định, nhưng được xác định bằng thực thi. Lỗi của tôi. –

Trả lời

21

C có các quy tắc khác nhau cho các hằng số thập phân, bát phân và thập lục phân.

Đối với số thập phân, nó là loại đầu tiên giá trị có thể phù hợp trong: int, long, long long

Đối với hệ thập lục phân, nó là loại đầu tiên giá trị có thể phù hợp trong: int, unsigned int, long, unsigned long, long long , unsigned long long

Ví dụ trên một hệ thống với 32-bitintunsigned int: 0x80000000unsigned int.

Lưu ý rằng đối với các hằng số thập phân, C90 có các quy tắc khác nhau (nhưng các quy tắc không thay đổi cho các hằng số thập lục phân).

+1

Câu trả lời đúng duy nhất cho đến nay. (Nits: bạn không chỉ định các quy tắc cho bát phân [xem hex], và từ C90, các hệ thập lục phân được thay đổi bằng cách bổ sung các loại 'long long'). –

+0

nhưng sau đó chúng tôi không thể mong đợi một lời cảnh báo trong 'int n = 0x80000000;' Bởi vì nó được gán một uint32_t đến một int32_t và bằng cách nào đó tràn? – mbonnin

+0

Điều này có nghĩa là tuyên bố "Một hằng số nguyên như 1234 là một int." trong [K & R2] là sai? –

9

Nó được ký nếu nó vừa với một số nguyên đã ký. Để làm cho nó không được ký, hãy thêm hậu tố u, ví dụ: 1234u.

Bạn có thể chuyển đổi giá trị đã ký thành unsigned bằng cách gán nó cho biến chưa ký.

unsigned int i = 1234u; // no conversion needed 
unsigned int i = 1234; // signed value 1234 now converted to unsigned 

Đối 0x80000000, nó sẽ được unsigned nếu ints là 32 bit trên nền tảng của bạn, vì nó không phù hợp với một int ký kết.


Một điều cần lưu ý khác là hành vi dịch chuyển phải phụ thuộc vào nền tảng. Trên một số nền tảng, đó là bảo quản bằng dấu (số học) và trên một số nền tảng, đó là một sự thay đổi bit đơn giản (logic).

+0

xem phần bổ sung của tôi –

+0

Được cập nhật để trả lời truy vấn bổ sung của bạn. –

+0

'0x80000000' chưa được ký nhưng chưa được ký trên hệ thống 32 bit và 64 bit. – ouah

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