2012-06-04 40 views
7

Ngôn ngữ tôi sử dụng là C. Loại x và n là int.Sự khác biệt giữa ~ (x-1) và ~ x + 1 khi x = 0x80000000

tôi có một dòng mã như sau

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

Nó cho thấy giá trị của x, n và hai phương pháp chuyển n bit của số bù của x. Khi x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000, nhưng khi chuyển hai số này bằng n bit, kết quả sẽ khác nhau.

btw, nếu tôi thay đổi 0xffffffff tới ~ 1 + 1 (có nghĩa là ~ (x + (~ 1 + 1)), kết quả là giống như ~ x + 1

Tôi tự hỏi tại sao điều đó xảy ra. Cảm ơn .

+0

[Là “(uint16_t) -1 ″ Mã C di động?] (Http://embeddedgurus.com/barr-code/2011/06/is-uint16_t-1-portable-c-code/) – Lundin

+0

@Lundin Bài viết đó sai. '(uint16_t) -1' ** được ** đảm bảo bởi chuẩn để tạo ra' 0xFFFF' nếu việc thực hiện cung cấp kiểu đó trong 'stdint.h'. (Tất nhiên, không có gì được đảm bảo nếu đó là typedef của riêng bạn.) Không có sự mơ hồ, các loại chiều rộng cố định được yêu cầu không có bit đệm, vì vậy nó không bị hạn chế đối với các bit giá trị (tốt, đó là, vì có chỉ là bit giá trị trong 'uintN_t'). –

Trả lời

4

Câu trả lời ngay bây giờ đã bị xóa bởi Pavan Manjunath có câu trả lời đúng cho một trường hợp, giả sử rằng int như thường lệ là loại 32 bit. Các hằng số nguyên

0xffffffff 

có giá trị 2^32 - 1 và rằng không thể thực hiện bởi một int, nhưng nó là biểu diễn như một unsigned int. Vì vậy, loại của nó là unsigned int (6.4.4.1). Do đó x được chuyển thành unsigned int cho việc bổ sung, và

((~(x+0xffffffff))>>n) 

đánh giá như

((~(0x80000000u + 0xffffffffu)) >> n) 
((~0x7fffffffu) >> n) 
(0x80000000u >> n) 

với giá trị 2^(31-n) nếu 0 <= n < 32 (đó là hành vi không xác định nếu n nằm ngoài phạm vi đó).

Đối với trường hợp khác, câu trả lời của ouah là chính xác, khi x = 0x80000000int, ~0x8000000 = 0x7fffffff = INT_MAXINT_MAX + 1 là hành vi không xác định là tràn số nguyên đã ký.

Tuy nhiên, một hành vi phổ biến là xung quanh, và sau đó kết quả của việc bổ sung là số nguyên đã ký 0x80000000 và dịch chuyển phải của số nguyên âm là hành vi được xác định thực hiện (6.5.7). Thông thường là dịch chuyển với phần mở rộng dấu, sẽ mang lại kết quả -2^(31-n), sau đó được hiểu là unsigned int với giá trị 2^32 - 2^(31-n) theo thông số printf chuyển đổi %x.

+0

là ~ 0 chữ ký hoặc chưa ký ... – shirley

+0

'0' có thể biểu diễn dưới dạng' int', do đó, kiểu '~ 0' cũng là' int'. –

1

Khi x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000,

Trên một hệ thống với 32-bit int (giả sử x là loại int) và bổ sung hai đại diện đã ký, biểu thức này:

~x+1 

là hành vi không xác định. x = 0x80000000 nghĩa là ~x == 0x7FFFFFFF == INT_MAXINT_MAX + 1 là hành vi không xác định. Vì vậy, ~x + 1 có thể là 0x80000000 hoặc bất kỳ thứ gì khác.

biểu này:

~(x+0xffffffff) 

mặt khác được định nghĩa (0xffffffffunsigned int trong C) và tương đương với 0x80000000. Nó thực sự được xác định bởi vì 0xffffffffunsigned int và các số nguyên không dấu không bao giờ tràn theo ý nghĩa của tiêu chuẩn C.

Điều này có nghĩa rằng tuyên bố này:

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

gọi hành vi undefined và nó làm cho không có ý nghĩa để so sánh cả hai kết quả.

0

(Giả sử sizeof (int) là 4; tức là, giá trị đã ký 32 bit). 0x80000000; // -2147483648 đó là nhỏ nhất có thể tiêu cực int 0xFFFFFFFF // là -1

Thêm hai cùng nhau gây ra một 'quấn quanh' từ âm sang dương 0x7FFFFFFF là tổng của hai (sử dụng int số học), trong đó là 2147483647

Sử dụng '~' điều hành trên 0x7FFFFFFF sản lượng một completent chút khôn ngoan, hoặc 0x80000000

Nếu bạn bắt đầu với bất kỳ giá trị int và trừ 1 từ nó (hoặc thêm 1 đến nó, nó không vấn đề) đủ thời gian, bạn sẽ làm cho nó lật dấu hiệu của nó. Đây là một vấn đề cơ bản với số học sử dụng độ chính xác cố định.

Trong trường hợp của bạn, bạn không thể mong đợi để trộn các toán tử số học và bitwise đã ký mà không cần phải chú ý đến trường hợp giới hạn này.Cũng lưu ý rằng có một bất đối xứng khi sử dụng số học bổ sung 2: có một số âm hơn số dương (vì bạn cần biểu diễn bằng không, để lại một số lẻ biểu diễn bit khác cho các giá trị còn lại.)

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