Question Details

No question body available.

Tags

c language-lawyer bit-manipulation standards c99

Answers (3)

Accepted Answer Available
Accepted Answer
May 3, 2026 Score: 6 Rep: 236,468 Quality: Expert Completeness: 60%

Summary

-(uintNt)x, (v & -v), and v & (~v+1) are not safe. Sample cases proving that are below.

v & - (uintmaxt) v is safe.

Details

From the title of the question:

-(uintNt)x

Consider x = 1, a uint16t cast, and a C implementation that uses a 32-bit one’s complement int. The desired result is the 32-bit two’s complement of 1, which is 11111111 11111111 11111111 111111112. In this situation, 1 will be converted to uint16t, which does not change the value, yielding 1. Then this uint16t value is promoted to int, again yielding 1. Then this int is negated. Since int is one’s complement, the result is 11111111 11111111 11111111 111111102, which is not the desired result.

From the body of the question:

(v & -v)

Consider v = 1 and a C implementation that uses a 32-bit one’s complement int. The desired result here is that -v produce the two’s complement, 11111111 11111111 11111111 111111112 and v & -v produce 1. In this situation, for -v, 1 will be negated in the one’s complement int, producing 11111111 11111111 11111111 111111102. Then the & will produce 0, which is not the desired result.

So the answer is no, neither of these code fragments is guaranteed to work as desired by the C 1999 standard.

C 2024 added a requirement that two’s complement be used (in clause 6.2.6.2), so the above two fragments would work in C 2024.

Also from the question:

If it's not guaranteed that two's complement arithmetic is used for unsigned inverse, what about v & (~v+1)?

This will work if the value of v is not too large in magnitude. However, it can fail even in two’s complement if v is large. Consider a C implementation with 32-bit two’s complement int and v = − 231 = 10000000 00000000 00000000 000000002. Then ~v produces 01111111 11111111 11111111 111111112. This the the maximum int value, 231−1. Then ~v+1 overflows, and the behavior is not defined by the C standard. However, this is safe as long as v is an unsigned type, since then it is either narrower than int and cannot produce a troublesome value or it so wide it will not be promoted to int.

Another problem case with v & (~v+1) is that ~v may produce a trap representation (essentially a bit pattern that is reserved to indicate it is not a value in the type). Then adding 1 to this trap representation would have undefined behavior. The trap representation would be 10000000 00000000 00000000 000000002 in sign-and-magnitude or two’s complement and 11111111 11111111 11111111 111111112 in one’s complement. The former can be produced from ~v when v has the unsigned int value 01111111 11111111 11111111 111111112, and the latter can be produced from 0, so v & (~v+1) is not always safe even when v has an unsigned type.

v & - (uintmax_t) v would work in C 1999, since then the negation would be done in an unsigned type that cannot be promoted to a signed type. A good compiler might optimize this to code that uses a smaller type when sufficient (especially if it is immediately converted to a narrower type).

May 3, 2026 Score: 2 Rep: 4,600 Quality: Low Completeness: 80%

I found something in the C standard that may be helpful here:

6.3.1.3 1: When a value with integer type is converted to another integer type other than Bool, if the value can be represented by the new type, it is unchanged.

6.3.1.3 2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

So, signed minus one converts to UINTMAX. Signed minus two converts to UINTMAX minus one.

Therefore, even if the implementation uses ones' complement or sign-and-magnitude (permitted by C99), and even if uint8t is promoted to int before the operations, the result is effectively dictated by two's complement arithmetic, and it can be guaranteed that (uint16t)-v is the same as (uint16t)(~v+1)

What I'm not sure about are the cases where promotion is not used. But I assume it is a good feature to have v + (-v) as zero even if v is not promoted to an int, and this would dictate "two's complement unsigned arithmetic" (in quotes since usually two's complement is intended for signed arithmetic, not for unsigned arithmetic). Maybe someone else can find the relevant parts in the standard.

May 3, 2026 Score: 2 Rep: 139,583 Quality: Low Completeness: 70%

Yes, -(uintNt) x is guaranteed to work modulo the appropriate power of 2. In addition to the sections @juhist quoted, it is also explained in the C 1999 standard, section 6.2.5 clause 9:

... 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.

This clause is also quoted in the discussion on this very related StackOverflow question:

C: unary minus operator behavior with unsigned operands