2009-09-12 44 views
8

Tôi không có cái này!unsigned long 0 <-1?

#include <stdio.h> 

int main() 
{ 
    unsigned short t1 = 0, t2 = 0; 

    if(t1 < t2-1) 
     printf(" t1 < t2-1\n"); 

    unsigned long s1 = 0, s2 = 0; 

    if(s1 < s2-1) 
     printf(" s1 < s2-1\n"); 
} 

này dẫn đến:

s1 < s2-1 

Hoặc cả hai nên thất bại hoặc cả hai không. Tôi đã thử điều này với gcc 4 & 4.2

+0

~ nairboon: Tôi hy vọng bạn không ngại chỉnh sửa. Mã tôi thay thế của bạn với chức năng giống nhau, nhưng có thể được sao chép/dán vào một trình soạn thảo và biên soạn mà không thay đổi. –

+1

Lưu ý rằng kết quả này không được đảm bảo là kết quả. Trên máy mà int lưu trữ cùng một phạm vi giá trị như ngắn (16 bit máy sẽ, tôi nghĩ), bạn sẽ thấy đầu ra cho cả hai ifs, bởi vì quảng cáo sẽ chuyển thành int không dấu sau đó, thay vì int. –

Trả lời

12

Ngôn ngữ C thực hiện việc "chuyển đổi số học thông thường" đối với nhiều nhà khai thác - các chuyển đổi được nêu trong 6.3.1.8 của tiêu chuẩn C99. Đối với các toán hạng tích phân, các chương trình khuyến mãi đầu tiên được thực hiện và đây là những gì gây ra sự cố của bạn. Các chương trình khuyến mãi được nêu trong 6.3.1.1 (Toán hạng số học/Boolean, ký tự và số nguyên), trong số đó có một số thứ khác:

Nếu int có thể đại diện cho tất cả các giá trị của kiểu gốc, giá trị được chuyển thành giá trị int; nếu không, nó sẽ được chuyển thành int không dấu. Đây được gọi là chương trình khuyến mãi số nguyên. Tất cả các loại khác không thay đổi bởi các chương trình khuyến mãi số nguyên.

Các chương trình khuyến mãi chỉ được áp dụng cho các đối tượng hoặc biểu thức với một kiểu số nguyên với một cấp bậc thấp hơn intunsigned int (hoặc bitfields).

Vì vậy, trong exression của bạn:

t1 < t2-1 

mặc dù các biến là unsigned short họ đang thăng int, vì trên nền tảng của bạn int thể đại diện cho tất cả các giá trị của unsigned short. Vì vậy, biểu thức được đánh giá bằng cách sử dụng các loại int và không có sự cố nào xảy ra - phần t2-1 của biểu thức kết thúc bằng âm 1.

Trong biểu thức:

s1 < s2-1 

các unsigned long loại không được thăng chức, bởi vì họ có một chữ 'rank' cao hơn int/unsigned int, vì vậy biểu thức được đánh giá bằng số học unsigned (với underflow từ phép trừ) và biểu thức phụ s2-1 đánh giá đến một số rất lớn, không phải là số âm 1.

Như đã nêu trong một nhận xét, nếu nền tảng đã thực hiện là kiểu 16 bit (được phép - MS-DOS cho ví dụ), người chuyên nghiệp chuyển động của unsigned short sẽ là unsigned int thay vì int, vì int sẽ không thể đại diện cho tất cả các giá trị của unsigned short (unsigned short phải ít nhất 16 bit). Trong trường hợp đó, cả hai câu lệnh if sẽ được đánh giá là đúng.

13

Tôi không chắc chắn nhưng tôi nghi ngờ rằng biểu thức t2-1 tự động được mở rộng thành giá trị int. Tôi không có tiêu chuẩn c ở đây quy tắc chuyển đổi chính xác là gì, nhưng tôi tin rằng các loại nhỏ hơn int được tự động mở rộng.

+3

+1, trong một biểu thức số học, các đối tượng của các loại (đã ký/unsigned) ngắn và (ký/unsigned /) char được * thăng * thành int. – avakar

+1

Câu trả lời này sẽ tốt hơn nhiều nếu bạn nói ** 't2' ** được chuyển thành int, chứ không phải **' t2-1' ** (để rõ ràng là chuyển đổi xảy ra * trước * trừ). –

3

C cưỡng chế, như bạn đang khám phá, không phải lúc nào cũng rõ ràng, bất cứ khi nào bạn hoạt động giữa các loại khác nhau. t2 là u16, 1int (có lẽ là 32 bit), vì vậy t2-1 chính xác là "hoạt động giữa các loại khác nhau" và dẫn đến sự ép buộc chung cho int (vì nó dài hơn u16 ...). Sau đó, khi s2 và 1 là cả hai bit 32 bit (mặc dù có chữ ký khác nhau), sự ép buộc tổng thể là không được ký kết lâu dài. Vì vậy, kích thước của các loại có liên quan sẽ giúp xác định sự ký kết của sự ép buộc tổng thể.

Tôi khuyên bạn nên tránh các ký hiệu hỗn hợp (và lý tưởng cũng là kích thước hỗn hợp!) (Thông qua đúc hoặc ký hiệu chữ đặc biệt cho các chữ như 1 nếu không sẽ có loại int và làm cho cuộc sống của bạn có thể phức tạp và mã của bạn có khả năng không thể chuyển đổi; -).

0

-1 được biểu thị bằng 1 giây. Vì vậy, khi được giải thích là unsigned, giá trị của nó là 2^32-1, rõ ràng là lớn hơn 0. Tôi đoán rằng so sánh đầu tiên được mở rộng để thực hiện số học 32-bit đã ký (có lẽ do "1" là một int đã ký).

Lưu ý rằng sau đây sẽ nhận được để printf, bởi vì so sánh hiện nay được thực hiện trong 16-bit không gian unsigned một lần nữa:

u32 temp = t2 - 1; 
if(t1 < temp) 
    printf(" t1 < t2-1\n"); 
+4

Chữ cái 1 (thuộc loại 'int') được chuyển thành 'unsigned long' trước phép trừ. Vì số học trên các kiểu unsigned luôn luôn được thực hiện modulo '2^k', đối với kiểu' k' cụ thể, kết quả là '2^k-1'. Biểu diễn của -1 không liên quan (và nó không nhất thiết phải là tất cả trên một số kiến ​​trúc). – avakar

+0

Biểu diễn -1 tham gia vào phần giải thích phần thứ hai: tại sao 0 <-1 trong khoảng thời gian chưa ký. – Yuliy

+0

Không. Giống như avakar nói, '-N' -> unsigned là một phép toán thuần túy, chỉ tính toán' UINT_MAX + 1 - N'. Không có đại diện được dựa vào bất cứ nơi nào. –

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