2011-11-06 35 views
29

Tôi dường như không thể tìm thấy các phần liên quan trong tiêu chuẩn C xác định đầy đủ hành vi của toán tử trừ đơn toán với toán hạng chưa ký.C: unary trừ hành vi của toán tử với toán hạng chưa ký

2003 chuẩn C++ (có, C++, gấu với tôi trong một vài dòng) nói trong 5.3.1c7: The negative of an unsigned quantity is computed by subtracting its value from 2^n, where n is the number of bits in the promoted operand.

Tiêu chuẩn 1999 C, tuy nhiên, không bao gồm một tuyên bố rõ ràng như vậy và không xác định rõ ràng hành vi đơn nhất không trong 6.5.3.3c1,3 cũng như trong 6.5c4. Trong sau này nó nói Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, ...) ... return values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed types.), trong đó không bao gồm trừ đơn và những thứ dường như vẫn còn mơ hồ.

This earlier question dùng để chỉ sách K & R ANSI C, mục A.7.4.5 có nội dung là The negative of an unsigned quantity is computed by subtracting the promoted value from the largest value of the promoted type and adding one.

Tiêu chuẩn C năm 1999 tương đương với báo giá ở trên từ sách là gì?

6.2.5c9 nói: A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

Có phải không? Hoặc có cái gì khác tôi đang mất tích?

+1

Có, đó là §6.2.5. –

+1

Kết quả của các toán tử '<<' and '>>' không phụ thuộc vào sự biểu diễn của các số nguyên. Chúng được định nghĩa là phép nhân và phép chia theo lũy thừa của hai và chỉ được định nghĩa rõ ràng cho các toán hạng không âm. '<<' là không xác định cho các toán hạng âm, và '>>' được định nghĩa thực hiện cho các toán hạng âm. –

+0

'Âm của một số chưa ký được tính bằng cách trừ giá trị được khuyến khích từ giá trị lớn nhất của loại được quảng bá và thêm một' - Tôi biết kung fu toán học của tôi yếu so với Ritchie và Stroustrup hùng mạnh, nhưng điều này có vẻ như người nghèo, và có lẽ điên rồ, cách để xử lý một tình huống chắc chắn là lỗi lập trình viên 99,9 ...% thời gian. Tại sao không ném một lỗi biên dịch nói rằng 'bạn đã cố gắng áp dụng một dấu hiệu cho một loại unsigned, bạn dingus'? – CCJ

Trả lời

14

Có, 6.2.5c9 chính xác là đoạn mà bạn đã tìm kiếm.

+3

Cách khác, người ta có thể xem toán tử phủ định như sinh ra nghịch đảo phụ của toán hạng của nó. Nếu N là unsigned, -N là tương đương với 1U + ~ N vì đó là giá trị mà, khi được thêm vào N, sẽ mang lại số không. – supercat

+0

@supercat Vì vậy, bạn được đảm bảo hành vi bổ sung của hai ngay cả khi phần cứng cơ bản sử dụng một đại diện khác nhau của các số âm? – JAB

+0

@JAB: Hai biểu diễn bổ sung xảy ra để khớp với các biểu diễn không dấu, nhưng định nghĩa về hành vi không liên quan gì đến sự bổ sung của hai. – supercat

4

Trong mỗi thực hiện tôi biết, một tiêu cực được tính như two's complement ...

int a = 12; 
int b = -a; 
int c = ~a + 1; 
assert(b == c); 

... do đó thực sự là không có sự khác biệt về thể chất giữa có chữ ký và số nguyên unsigned "tiêu cực" tiêu cực - sự khác biệt duy là cách họ được diễn giải.

Vì vậy, trong ví dụ này ...

unsigned a = 12; 
unsigned b = -a; 
int c = -a; 

... các bc sẽ chứa các bit chính xác tương tự. Sự khác biệt duy nhất là b được hiểu là 2^32-12 (hoặc 2^64-12), trong khi c được hiểu là "bình thường" -12. Vì vậy, một âm tính được tính theo cùng một cách bất kể "ký hiệu" và việc truyền giữa unsigned và signed thực sự là một no-op (và không bao giờ có thể gây tràn theo ý nghĩa rằng một số bit cần để được "cắt").

+8

Tôi biết tất cả những gì từ thực hành là tốt. Câu hỏi đặt ra là một điều khác, hành vi theo tiêu chuẩn. –

+0

Tôi không biết điều này và nó có vẻ là công cụ nền tảng, ta. +1 –

5

Hành vi của toán tử trừ đơn trên toán hạng chưa ký không liên quan gì đến việc máy tính sử dụng số học bổ sung của hai với số đã ký. Thay vào đó, được đưa ra unsigned int x,y; tuyên bố y=-x; sẽ gây ra y để nhận bất kỳ giá trị nào mà nó sẽ phải giữ để thực hiện x+y bằng không. Nếu x bằng 0, y tương tự sẽ bằng không. Đối với bất kỳ giá trị nào khác của x, nó sẽ là UINT_MAX-x+1, trong trường hợp đó giá trị số học là x+y sẽ là UINT_MAX+1+(y-y), khi được gán cho unsigned integer, sẽ bị trừ UINT_MAX+1 trừ nó.

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