jbn@wdl1.UUCP (John B. Nagle) (06/13/84)
The painful effort to make C portable continues. It is unfortunate that we don't have "signed char" as well as "unsigned char" syntax, so that if you really needed unsigned or signed chars, you could say so, in which case the compiler should give it to you, even if it is slow. Some time ago (back when Ada was called DOD-1) I was promoting the idea that ranges are really the way to go, and that this "short" and "long" and "long long" (Algol-68) business was all wrong. My ideal is as follows. Numeric variables are declared by giving a lower and upper bound for their value. There may be predefined types such as "int", but these are just predefined ranges, not fundamental objects of the language. These definitions are independent of the machine being used. Overflow is an error. Checking should be available. Where hardware checking is available (as on VAXen), it should always be on. (For amusement, build a VAX C compiler with the integer overflow check enable bit turned on in the entry mask, and see how many standard programs blow up when compiled with it.) This implies that you can't do checksums, hashing, etc. with the standard arithmetic operators. This is OK, you just need some built-in functions like "addmod(a,b,base)" that generate good open code when "base" is a constant and a power of two. The type of a constant N is N..N; The type of an expression must accomodate the largest value that can be generated by the values in that expression. Thus, if X and Y have range 0..256 then X*Y has range 0..65536 and X*Y*Y has range 0..16777216 But if the compiler sees X = X*Y it can optimize, and only do an 8-bit unsigned multiply, because the result has to fit in 8 bits. So you don't need multiple precision arithmetic for all the simple expressions. But X=X*X*X*X*X*X/(Y*Y*Y*Y*Y*Y) would probably be considered illegal as an expression because the intermediate range would exceed the machine limits. The compiler has to see the procedure definition to generate the call; C suffers from this; we have to pass 32 bits on a M68000 every time we want to pass a flag. It simplifies the compilation problem, but I would rather have the checking. When there are lots of numeric types, though, you need to see the definition at compile time, or you need lots of casts. What you get from all this is that you get the same answer on all machines, regardless of the hardware available. The compiler has to work harder, but the code is a lot more portable. Something to think about when it is time to define ``D''.