This should probably carry a date stamp; my guess would be that it dates from 1990 or so.
Most of the advice is still good, but I would object to (3):
* Excessive casting can be a problem in itself, as it hides genuine type errors (e.g. you think you're casting an int to long, but in reality the variable is a pointer)
* Casting NULL is pointless, as it's already defined by the standard to be a pointer constant, compatible with all data pointers.
* Much of the language about "prototypes" (a.k.a. standard C) was justified at the time, but no longer reflects reality nowadays. It would have to be a very exotic platform that still uses a pre-ANSI C compiler.
Dated? #10 is from a 1980's MOTD message of the day:
All the world's a VAX,
And all the coders merely butchers;
They have their exits and their entrails;
And one int in his time plays many widths,
His sizeof being N bytes. At first the infant,
Mewling and puking in the Regent's arms.
And then the whining schoolboy, with his Sun,
And shining morning face, creeping like slug
Unwillingly to school.
-- A Very Annoyed PDP-11
Heh. Getting a response from you must be peak 1990 ;-)
By the time I got started on Usenet "All the world's a VAX" was only in use as a proverbial misconception anymore. At the time, all the world was a Sun Workstation.
>* Casting NULL is pointless, as it's already defined by the standard to be a pointer constant, compatible with all data pointers.
You should still cast NULL when passed as an unnamed argument to a variadic function. While NULL is defined to be a null pointer constant, that doesn't mean it has a pointer type (all integer literals with a value of zero are null pointer constants in C, but they have an integer type).
(Strictly speaking, all unnamed pointer arguments to variadic functions should be converted to a compatible pointer type that the variadic function expects. For example, the printf-line of functions expect a pointer-to-void argument for a conversion specifier %p. If you pass a pointer-to-int instead, technically the behaviour is undefined.)
(To whom it may concern: I would appreciate at least a rebuttal. It's not like this is a subjective matter.)
It's unfortunate that you're getting downvoted; there's for sure real dragons at the intersection of the NULL literal and variadic functions since it's totally legal for NULL to be defined as such:
You're right, I was misinterpreting the language of the standard.
As a practical matter, C implementations typically define NULL as a void pointer, so the cast is not necessary in those implementations (In C++ pre C++11, NULL is always defined as a literal 0, so the cast is definitely necessary).
But it appears the standard allows C implementations to define NULL as a literal 0 or as 0L as well, so the cast is needed in portable code.
Subject: Ten Commandments For C Programmers
Message-ID: <8771@utzoo.UUCP>
Date: Wed, 14-Oct-87 17:35:26 EDT
Subject: The Ten Commandments for C Programmers (Annotated Edition)
Message-ID: <1990Nov4.021618.24681@zoo.toronto.edu>
Date: 4 Nov 90 02:16:18 GMT
> It would have to be a very exotic platform that still uses a pre-ANSI C compiler.
Not "exotic" so much, really. Obviously those days are long behind us now, but for many years the very last refuge of K&R C was the bootstrap compiler for gcc.
By the 90's, for revenue and product differentiation reasons all the big Unix vendors had moved their optimizing toolchains into their "developer" software packages and out of the base system. But for legacy compatibility reasons they still needed a working K&R C compiler in /bin/cc.
So for almost two decades, the only contact working engineers had with pre-ANSI compilers was using them to bootstrap a real compiler (gcc) on their new, fancy, high performance, very mainstream and non-exotic workstations.
I dislike implicit type conversions, but I think every cast needs to be accompanied by an assertion. Just sprinkling casts everywhere does nothing but silence important compiler warnings.
An interesting thing about the old system is that it could have checked data types just fine. This would have required linker support, but in the early years C didn't have the influence to make that happen. It would have been the tail wagging the dog. Linkers were designed for other languages, then used by C.
With linker support, C++ would never have had to resort to name mangling.
The foo(i,j) in your example could have caused the compiler to emit assembly directives to specify the argument types and return type. The assembler could have put these into the object file. The linker could have checked for compatibility when linking. The linker could have produced warnings, errors, or in some cases even thunks.
From the following passage, I would have thought this would have been written as recently as today.
> As a lamentable side issue, there has been some unrest from the fanatics of the Pronoun Gestapo over the use of the word ``man'' in this Commandment, for they believe that great efforts and loud shouting devoted to the ritual purification of the language will somehow redound to the benefit of the downtrodden (whose real and grievous woes tendeth to get lost amidst all that thunder and fury). When preaching the gospel to the narrow of mind and short of temper, the word ``creature'' may be substituted as a suitable pseudoBiblical term free of the taint of Political Incorrectness.
#3 sounds extremely obsolete. I don't completely understand what they mean, but perhaps they are thinking pre-C89, when it wasn't as common to list the args in function declarations, so the compiler could not always correctly convert the type?
I remember in the 90s some libraries (like X11 headers) would put the types of function arguments inside an ifdef to be able to compile in some archaic place.
Edit: or maybe they are thinking of varargs. This could still be an issue with printf today.
I, for one, prefer my bibles with interspersed lines of Ancient Greek, so that you can interpret yourself. Our language will never keep changing, but the source remains the same.
The Ten Commandments were originally written in ancient Hebrew. They were passages in the Hebrew Bible, which the Christians later adopted as the Old Testament. It was the New Testament that was originally written in Greek.
"If thy header files fail to declare the return types of thy library functions, thou shalt declare them thyself with the most meticulous care, lest grievous harm befall thy program.
The prophet Ansi, in her wisdom, hath added that thou shouldst also scourge thy Suppliers, and demand on pain of excommunication that they produce header files that declare their library functions. For truly, only they know the precise form of the incantation appropriate to invoking their magic in the optimal way."
This commendment made me afraid of the dark. Was it common in those days to have to guess to calling convention of libfunctions?
Most of the advice is still good, but I would object to (3):
* Excessive casting can be a problem in itself, as it hides genuine type errors (e.g. you think you're casting an int to long, but in reality the variable is a pointer)
* Casting NULL is pointless, as it's already defined by the standard to be a pointer constant, compatible with all data pointers.
* Much of the language about "prototypes" (a.k.a. standard C) was justified at the time, but no longer reflects reality nowadays. It would have to be a very exotic platform that still uses a pre-ANSI C compiler.
By the time I got started on Usenet "All the world's a VAX" was only in use as a proverbial misconception anymore. At the time, all the world was a Sun Workstation.
You should still cast NULL when passed as an unnamed argument to a variadic function. While NULL is defined to be a null pointer constant, that doesn't mean it has a pointer type (all integer literals with a value of zero are null pointer constants in C, but they have an integer type).
(Strictly speaking, all unnamed pointer arguments to variadic functions should be converted to a compatible pointer type that the variadic function expects. For example, the printf-line of functions expect a pointer-to-void argument for a conversion specifier %p. If you pass a pointer-to-int instead, technically the behaviour is undefined.)
(To whom it may concern: I would appreciate at least a rebuttal. It's not like this is a subjective matter.)
As a practical matter, C implementations typically define NULL as a void pointer, so the cast is not necessary in those implementations (In C++ pre C++11, NULL is always defined as a literal 0, so the cast is definitely necessary).
But it appears the standard allows C implementations to define NULL as a literal 0 or as 0L as well, so the cast is needed in portable code.
But if you cast the intptr to voidptr, the behavior is defined, right? (Besides that %p is nonstandard iirc)
Not "exotic" so much, really. Obviously those days are long behind us now, but for many years the very last refuge of K&R C was the bootstrap compiler for gcc.
By the 90's, for revenue and product differentiation reasons all the big Unix vendors had moved their optimizing toolchains into their "developer" software packages and out of the base system. But for legacy compatibility reasons they still needed a working K&R C compiler in /bin/cc.
So for almost two decades, the only contact working engineers had with pre-ANSI compilers was using them to bootstrap a real compiler (gcc) on their new, fancy, high performance, very mainstream and non-exotic workstations.
What do you think of "auto" in C++ ?
The following C code compiles today without complaint on gcc:
With linker support, C++ would never have had to resort to name mangling.
The foo(i,j) in your example could have caused the compiler to emit assembly directives to specify the argument types and return type. The assembler could have put these into the object file. The linker could have checked for compatibility when linking. The linker could have produced warnings, errors, or in some cases even thunks.
> As a lamentable side issue, there has been some unrest from the fanatics of the Pronoun Gestapo over the use of the word ``man'' in this Commandment, for they believe that great efforts and loud shouting devoted to the ritual purification of the language will somehow redound to the benefit of the downtrodden (whose real and grievous woes tendeth to get lost amidst all that thunder and fury). When preaching the gospel to the narrow of mind and short of temper, the word ``creature'' may be substituted as a suitable pseudoBiblical term free of the taint of Political Incorrectness.
This one is a universal experience. :)
edit: ...my wrath follows, and it shall go BAM!
I remember in the 90s some libraries (like X11 headers) would put the types of function arguments inside an ifdef to be able to compile in some archaic place.
Edit: or maybe they are thinking of varargs. This could still be an issue with printf today.
Should be “when thou expectest it least”
lest thou tear thy hair
Should be “lest thou tearest thine hair” as I seem to recall the h sound acting like vowel for words that sound different based on what follow them.
lest grievous harm befall thy program.
Should be “befalleth”
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...
The prophet Ansi, in her wisdom, hath added that thou shouldst also scourge thy Suppliers, and demand on pain of excommunication that they produce header files that declare their library functions. For truly, only they know the precise form of the incantation appropriate to invoking their magic in the optimal way."
This commendment made me afraid of the dark. Was it common in those days to have to guess to calling convention of libfunctions?