2010-11-17 28 views
8

Tôi đã tìm kiếm trang này để tìm câu trả lời và tìm thấy nhiều câu trả lời cho so sánh chưa ký/đã ký nhưng vấn đề này chỉ là các thông số chưa được so sánh nhưng vẫn hoạt động được.unsigned sẽ được ký kết trong các so sánh if-statement?

Sự cố với mã sau đây là số if đầu tiên không xảy ra ("xin chào") trong trường hợp thứ hai ("thế giới") thực hiện. Điều này tôi đã giải thích khi tính toán được thực hiện bên trong các if -statment tạo ra một số âm nhưng tính toán chính xác tương tự được thực hiện với kết quả được lưu vào một biến không (mặc dù kết quả đang được lưu vào một biến ký).

Trình biên dịch được sử dụng là gcc 4.4.

unsigned short u16_varHigh; 
unsigned short u16_varLow; 
unsigned short u16_Res1; 
signed short s16_Res1; 

u16_varHigh = 0xFFFF; 
u16_varLow = 10; 

u16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected 
s16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected 

// Does not enter 
if((u16_varLow - u16_varHigh) > (unsigned short)5) 
{ 
printf("hello"); 
} 

// Does enter 
if((unsigned short)(u16_varLow - u16_varHigh) > 5) 
{ 
printf("world"); 
} 

Bất cứ ai có thể giải thích điều này cho tôi và có thể đưa ra giải pháp để sửa chữa sao cho hoạt động đầu tiên của if cũng có hiệu quả không?

+0

thể trùng lặp của (http [Câu hỏi về quy tắc khuyến mãi không thể thiếu C.]: // stackoverflow .com/questions/2280663/question-about-c-integral-promotion-rules) – unwind

+3

Tôi không đồng ý. Về chủ đề tương tự, nhưng không trùng lặp. – Kos

Trả lời

4

Trong biểu thức:

if((u16_varLow - u16_varHigh) > (unsigned short)5) 

(u16_varLow - u16_varHigh) sẽ được đề bạt lên một int và đánh giá để -65.525. Việc khắc phục sự cố của bạn là truyền sang loại không dấu, giống như bạn thực hiện trong mã "Không nhập".

Lý do s16_Res1 = u16_varLow - u16_varHigh; sản lượng 11 là kết quả của phép trừ, -65525, không vừa trong ngắn.

+0

Nó thực sự là 'u16_varLow' và' u16_varHigh' được quảng bá riêng lẻ thành 'int', trước phép trừ. – caf

+0

Có hai phôi riêng lẻ được thực hiện không? Câu lệnh if sau sẽ không được nhập: u16_varHigh = 0xff00;
nếu (u16_varHigh <-5) ... Quyết định ký tên là do chất nền. Vì vậy, so sánh một unsigned (với bit cao thiết lập) sẽ được coi là unsigned, nhưng so sánh sự khác biệt giữa 2 unsigned một nó được coi là đã ký kết. Nó cảm thấy sai bằng cách nào đó ... – Wilmer

+0

Nó cũng đáng chú ý là '(unsigned short)' không có hiệu lực (trên một máy 32-bit). '(unsigned short) 5' được nâng lên' int' trước khi được coi là đầu vào cho phép so sánh, nếu tất cả các giá trị của 'unsigned short' phù hợp với' int'. Nếu bạn đã làm điều này trên một bộ xử lý trong đó ngắn và int có chiều rộng tương tự, '(unsigned short) 5' sẽ quảng bá đến' unsigned', như các lhs, và điều kiện sẽ đúng. – greggo

1

Đầu tiên, if((u16_varLow - u16_varHigh) > (unsigned short)5) sẽ không bao giờ chuyển, vì số (u16_varLow - u16_varHigh) trả về số âm, vì số này được coi là số nguyên. Cái thứ hai tạo ra cùng một số âm, không được ký tắt ngắn, đó là lý do nó vượt qua.

Lưu ý - bạn biết rằng tất cả điều này phụ thuộc vào nền tảng, phải không? Kích thước của short, int, v.v. phụ thuộc vào nền tảng bê tông.

+0

@Lưu ý: Tôi nhận thức được điều này nhưng tôi cảm ơn bạn anyway (Bởi vì tôi đã không nhận thức được điều này, bạn đã có thể tiết kiệm cho tôi rất nhiều công việc) – Wilmer

2

Trong các câu trả lời khác mà chúng tôi đã thấy rằng

u16_varLow - u16_varHigh 

cho bạn (với 16 bit short và 32 bit int) tương đương với

(int)u16_varLow - (int)u16_varHigh 

và do đó kết quả của nó là int giá trị -65525 . Như vậy việc chuyển nhượng

s16_Res1 = u16_varLow - u16_varHigh; 

tương đương với

s16_Res1 = -65525; 

mà trong trường hợp của bạn của 16 bit short mang lại "hành vi không xác định". Bạn chỉ là không may mắn rằng trình biên dịch của bạn quyết định gán 11, thay vào đó. (Không may mắn vì tôi nghĩ rằng nó là tốt hơn để không sớm).

Ngược lại với điều đó

u16_Res1 = -65525; 

là một nhiệm vụ có hiệu lực kể từ u16_Res1 là một kiểu unsigned và số học của các loại unsigned là modulo sức mạnh thích hợp của hai.

2

Trong "chuyển đổi số học thông thường", các loại nhỏ hơn int được thăng cấp thành int hoặc unsigned int trước khi chúng được sử dụng trong hầu hết các biểu thức. Quy tắc là nếu int có thể đại diện cho tất cả các giá trị của loại nhỏ hơn, thì nó được thăng cấp thành int; nếu không thì nó được thăng cấp thành unsigned int. Điều này thường được coi là một cái gì đó của một mụn cóc, bởi vì trong nhiều trường hợp nó gây ra các giá trị unsigned charunsigned short để được thăng cấp thành int.

Đây là chính xác những gì bạn đang thấy - u16_varLowu16_varHigh(unsigned short)5 đều thăng int trước khi trừ và so sánh, sau đó xảy ra bằng int. Nếu bạn muốn chắc chắn rằng một biểu thức sẽ sử dụng số học unsigned, bạn phải làm điều đó trong unsigned int, khôngunsigned short:

if(((unsigned)u16_varLow - (unsigned)u16_varHigh) > 5U) 
Các vấn đề liên quan