On Tue, Jan 3, 2017 at 12:19 PM, Doug McIlroy <doug@cs.dartmouth.edu> wrote:
> keeping the code I work on portable between Linux and the Mac requires
> more than a bit of ‘ifdef’ hell.

Curmudgeonly comment: I bristle at the coupling of "ifdef" and "portable".
Ifdefs that adjust code for different systems are prima facie
evidence of NON-portability. I'll buy "configurable" as a descriptor
for such ifdef'ed code, but not "portable".

And, while I am venting about ifdef:
As a matter of sytle, ifdefs are global constructs. Yet they often
have local effects like an if statement. Why do we almost always write

#ifdef LINUX
        linux code
#else
        default unix code
#endif

instead of the much cleaner

        if(LINUX)
                linux code
        else
                default unix code

In early days the latter would have cluttered precious memory
with unfreachable code, but now we have optimizing compilers
that will excise the useless branch just as effectively as cpp.


I have seen an interesting failure for the latter construct; I was compiling some [unremembered] chess program for some [unremembered] UNIX workstation in the late '80s.

The code had bit array data structures with get/set routines that optimized for host word size, with code something like:

    if (sizeof (unsigned int) == 64)
        {
           // cast structure into array of 64 bit unsigned ints and use bit operators
        }
    else  // sizeof (int) == 32
        {
           // cast structure into array of 32 bit unsigned ints and use bit operators
        }

(It might of been 32/16; I don't remember, but it isn't relevant)

The '64' branch had an expression containing something like  '1u << 60' in it.

I was compiling on a 32 bit int machine; the compiler flagged the '1u << 60' as a fatal error due to the size of the shift -- on this compiler the expression evaluator was running before the dead code remover.

-- Charles