سؤال

I can't seem to find the relevant parts in the C standard fully defining the behavior of the unary minus operator with unsigned operands.

The 2003 C++ standard (yes, C++, bear with me for a few lines) says in 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.

The 1999 C standard, however, doesn't include such an explicit statement and does not clearly define the unary - behavior neither in 6.5.3.3c1,3 nor in 6.5c4. In the latter it says 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.), which excludes the unary minus and things seem to remain vague.

This earlier question refers to the K&R ANSI C book, section A.7.4.5 that says The negative of an unsigned quantity is computed by subtracting the promoted value from the largest value of the promoted type and adding one.

What would be the 1999 C standard equivalent to the above quote from the book?

6.2.5c9 says: 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.

Is that it? Or is there something else I'm missing?

هل كانت مفيدة؟

المحلول

Yes, 6.2.5c9 is exactly the paragraph that you looked for.

نصائح أخرى

The behavior of the unary minus operator on unsigned operands has nothing to do with whether a machine uses two's-complement arithmetic with signed numbers. Instead, given unsigned int x,y; the statement y=-x; will cause y to receive whatever value it would have to hold to make x+y equal zero. If x is zero, y will likewise be zero. For any other value of x, it will be UINT_MAX-x+1, in which case the arithmetic value of x+y will be UINT_MAX+1+(y-y) which, when assigned to a unsigned integer, will have UINT_MAX+1 subtracted from it, yielding zero.

In every implementation I know of, a negative is calculated as two's complement...

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

...so there is really no physical difference between negative signed and "negative" unsigned integers - the only difference is in how they are interpreted.

So in this example...

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

...the b and c are going to contain the exact same bits. The only difference is that b is interpreted as 2^32-12 (or 2^64-12), while c is interpreted as "normal" -12.

So, a negative is calculated in the exact same way regardless of "sign-ness", and the casting between unsigned and signed is actually a no-op (and can never cause an overflow in a sense that some bits need to be "cut-off").

This is late, but anyway...

C states (in a rather hard way, as mentioned in other answers already) that

  • any unsigned type is a binary representation with a type-specific number of bits

  • all arithmetic operations on unsigned types are done (mod 2^N), 'mod' being the mathematical definition of the modulus, and 'N' being the number of bits used to represent the type.

The unary minus operator applied to an unsigned type behaves as if the value would have been promoted to the next bigger signed type, then negated, and then again converted to unsigned and truncated to the source type. (This is a slight simplification because of integer promotion happens for all types that have fewer bits than 'int', but it comes close enough I think.)

Some compilers do indeed give warnings when applying the unary minus to an unsigned type, but this is merely for the benefit of the programmer. IMHO the construct is well-defined and portable.

But if in doubt, just don't use the unary minus: write '0u - x' instead of '-x', and everything will be fine. Any decent code generator will create just a negate instruction from this, unless optimization is fully disabled.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top