Keith Thompson said:
Which raises a perhaps interesting question. Are there any current C
implementations for ones'-complement or sign-and-magnitude systems?
If so, what standard, if any, do they conform to, and how much
extra work do the compilers actually do to conform to the required
semantics for signed-to-unsigned conversion? For that matter,
are there non-conforming C implementations for such systems that
implement such conversions just by reinterpreting the bits?
There is one that does both (selectable as an option). I just happened
to be reading a Unisys C manual[1] recently. It's part of MCP: Unisys's
OS that runs on big machines derived from a Burroughs architecture. It
has 48-bit words and 8-bit bytes.
sizeof char/unsigned char/signed char is 1
sizeof long double is 12
sizeof everything else is 6
Despite having 48 bits, all integer types have 39 value bits. Signed
types have, in addition, a sign bit (presumably the 40th). The
remaining bits are presumably related to the tagged architecture that
Burroughs machines have always had and, as far as C goes, will be
padding bits. These machine will definitely have trap-representations,
since some sets of these tag bits are designed to cause traps in certain
situations.
The C implementation has INT_MAX == UINT_MAX and INT_MIN = -INT_MAX and
uses sign-magnitude representation. It supports ANSI C and it documents
the standard conversion from signed to unsigned types but, later on, in
a section on porting software it says:
Operations on unsigned integer types are more expensive than on signed
types. The $RESET PORT (UNSIGNED) option makes unsigned equivalent to
signed types and should be used on programs that do not depend upon
the wraparound or bit operation properties of unsigned types.
The document for this options says:
The UNSIGNED option controls the semantics of the sign attribute for
integer types. If this option is disabled, unsigned integers are
treated as signed integers; that is, normal signed-magnitude
arithmetic is performed. If the option is enabled, unsigned integers
are emulated as two’s- complement quantities. Enabling this option
could slow down performance and should be used only when absolutely
necessary.
For those who wonder about all the oddities in the standard, here is a
system that (a) uses EBCDIC[2]; (b) has unusual sizes and limits; (c) is
not two's complement; (d) has padding bits in all integer types except
the char types; (e) has trap representations in these types; and (f) has
multiple pointer representations (so pointer casts often generate code).
What's more it's *current*: there was recently an MCP 13.0 release with
support into 2013.
Given that the C standard has usually avoided mandating behaviour that
is expensive on some hardware, the behaviour of unsigned is an anomaly.
There was, however, little option since K&R mandated that behaviour long
before ANSI C.
[1]
http://public.support.unisys.com/aseries/docs/clearpath-mcp-13.0/pdf/86002268-204.pdf
[2] Though I think you can switch to ASCII if your program needs it.