C should also make char unsigned (D does). Optionally signed chars are an abomination.
C should also make char unsigned (D does). Optionally signed chars are an abomination.
The peculiar vagueness of the early C standards with respect to integers was probably due to the variety of hardware we used in the 1970s. For example:
The CDC 6000/7000s had 60-bit words, ones compliment arithmetic, 6 bit chars (but machine addresses were only of the 60 bit words).
The peripheral processors of the CDC machines (responsible for I/O) had 12-bit words as I recall.
IBMs very popular 360 mainframes supported several native hardware number formats: twos complement, unsigned, zoned decimal (one decimal digit per 8-bit byte), and packed decimal (two digits per byte).
I believe C was first developed on the DEC PDP-11. This was a very popular computer with 16 bit words and 8 bit bytes. It was twos complement, but mixed endianess (big endian for the 16 bit words making up a 32-bit long and little endian for the bytes in the 16-bit words).
Other DEC computers of the 1960s used 12 bit program counters and accumulators; I did some assembly language programming on the PDP-6 (it cost $300,000 back then and 24 were sold).
I seem to recall using a system with 18 bit registers and 9 bit bytes, but I can’t remember the details.
One system that I did assembly language programming on for a year was the TI 960. This machine was notable because it had two separate 64KB address spaces, one for data and one for instruction, known as a Harvard architecture instead of Von Neumann architecture. The advantage of the Harvard architecture was that a program couldn’t inadvertently modify the code it was running, a frequent and difficult to untangle occurrence when programming assembly. The Von Neumann architecture became dominant because it didn’t chop the available memory in two and partly because self modifying code was believed to be sometimes useful (yikes).
Unisys OS 2200 uses one's complement[1] and Unisys MCP uses signed magnitude[2]. Both are still around.
[1] - https://public.support.unisys.com/2200/docs/CP19.0/78310422-... (page 108) - "UCS C represents an integer in 36-bit ones complement form (or 72-bit ones complement form, if the long long type attribute is specified)."
[2] - https://public.support.unisys.com/aseries/docs/ClearPath-MCP... (page 304) - "ClearPath MCP C uses a signed-magnitude representation for integers instead of two’s-complement representation. Furthermore, ClearPath MCP C integers use only 40 of the 48 bits in the word: a separate sign bit and the low order 39 bits for the absolute value."
Rust gets points in my book for being more explicit and avoiding arbitrary promotion rules. Plus the standard lib has specific functions for things like add with overflow which reflect what the CPU flags are doing.
True. I've done a lot of assembler programming. Getting the right jxx instruction after a compare was a prolific source of bugs. I've had a lot fewer bugs with signed types :-)
> Plus the standard lib has specific functions for things like add with overflow which reflect what the CPU flags are doing.
D does, too:
https://dlang.org/phobos/core_checkedint.html
along with integer types that automatically check for overflow: