How does C treat the number 0 in a one’s complement architecture?

China☆狼群 提交于 2019-12-04 13:57:48

It is implementation-defined whether, on a ones-complement architecture, the value "with sign bit and all value bits 1" is a "trap representation" or a normal value. If it is a trap representation, any attempt to do anything with it, or even create it in the first place, provokes undefined behavior. If it is a normal value, it is a "negative zero", and there is an explicit list of operations that are allowed to produce it:

If the implementation supports negative zeros, they shall be generated only by:

  • the &, |, ^, ~, <<, and >> operators with operands that produce such a value;
  • the +, -, *, /, and % operators where one operand is a negative zero and the result is zero;
  • compound assignment operators based on the above cases.

It is unspecified whether these cases actually generate a negative zero or a normal zero, and whether a negative zero becomes a normal zero when stored in an object.

(C11/N1570, section 6.2.6.2 paragraph 3.)

It also appears to be unspecified (by omission) whether negative zero compares equal to normal zero. Similar rules apply to sign-and-magnitude architectures.

So, what this boils down to is, the behavior of your example code is implementation-defined, and the implementation may not define it helpfully. You would need to consult the compiler and architecture manuals for this hypothetical ones-complement machine to figure out whether it does what you want it to do.

However, the entire question is moot, because nobody has manufactured a non-twos-complement CPU in at least 25 years. One hopes that a future revision of the C standard will cease to allow for the possibility; it would simplify many things.

To answer your question, there are 2 possibilities to consider:

  • if the bit pattern with all bits set is a trap representation (which is explicitly allowed by the C Standard), passing such a value to the function has undefined behavior.

  • if this bit pattern is allowed, it the one's complement representation of negative zero, which should compare equal to 0. In this case, the function as written will have defined behavior and will return 0 since the initial loop test is false.

The result would be different if the function was written this way:

int bitcount32(int x) {
    // naive implementation assuming 31 value bits
    int count = 0, b;
    for (b = 0; b < 31; b++) {
        if (x & (1 << b))
           count++;
        }
    }
    return count;
}

On this one's complement architecture, bitcount32(~0) would evaluate to 31:

(x & (1 << b)) with x the argument with the specific bit pattern and b in range for 1 << b to be defined, evaluates to 1 << b, a different value from the result on two's complement and sign/magnitude architectures.

Note however that the posted implementation has undefined behavior for an argument of INT_MIN as x-1 causes a signed arithmetic overflow. It is highly advisable to always use unsigned types for bitwise and shift operations.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!