This is actually quite a laugh. Compiling the author's recommended "best" hello world on Mac OS 10.6 (gcc 4.2.1) yields this:
% a.out
Hello World!
ERROR: fputs did not succeed in writing our message string (error returned: Unknown error: 0)!
A look at the man page for puts shows that the author bungled the test for error:
fputs() now returns a non-negative number (as opposed to 0) on successful completion. As a result, many tests (e.g., "fputs() == 0", "fputs() != 0") do not give the desired result. Use "fputs() != EOF" or "fputs() == EOF" to determine success or failure.
Not so much bungled as got bitten by a change in behavior. Amusingly, “Return Values” still states the old behavior, to which standard the program is correct.
I'll fix the program.
By the way, the zip archives include a Makefile with correct compiler configuration (namely -std=c99). I tried downloading them after seeing this thread and it didn't work; I've re-uploaded them and now they download correctly, Makefiles and all. No more having to run the compiler by hand.
Ouch. Now the article isn't just advocating overengineering, it's just plain wrong - have you contacted the author to let him know? Probably best for him to fix this up asap.
And I hope all this criticism isn't too down-heartening... at least from my part (though I strongly believe it is the same for others too) it's intended as friendly and genuine constructive criticism.
Not at all. I always welcome constructive criticism; any opportunity to improve myself, I much appreciate. For my part, any criticism I offer, including the linked article itself, I likewise intend to be constructive.
BTW, I got the string "Hello Worldp" from the first program, using the same compiler configuration. I had to use std=c99 to get it to compile (the variable in the for loop).
The "best" is way overengineered. I doubt this error-handling will even work. If the program fails to print "hello world" using puts then it is very likely to fail on fprintf to stderr.
Only if both stdout and stderr are unwritable. If stdout is unwritable but stderr is writable, then writing to stderr should work.
If they're both not writable, or stderr is writable but writing fails anyway, there's nothing we can do about it anyway, but that does not make it any less proper to try.
I get the point, and it's important to point out to beginners the various subtleties of error checking, etc. - but to me the 'best possible' hello world is rather overengineered, I mean 4 includes to begin with... :-)
And dude, don't go using the word 'worst' as lightly as that. It's dangerous - I am sure we could make it ohhh really quite worse... how about relying on some known compiler/os bugs to flip some bits somewhere, obfuscating it right up then generate some code by repeating various pointless operations (but all slightly subtly randomly different so not obvious enough to remove) to get it to say ~ 5 million lines of code? :-D
If we tried to pour the collective total of human stupidity (artificial or otherwise) into a single program, it would exceed the capacities of all the storage devices ever made, past, present, and future. :-)
Honestly, if I were writing this today, I'd make the “worst” example less bad. What you see here is way too fantastic. 2011 Me would make it realistically bad—the sort of thing a new or just plain apathetic programmer might write. I wonder, though, how much it would differ from the canonical one-liner.
I've updated the page to version 0.3, with a fixed and improved “Best” example and some improvements to the text, based mostly on the feedback from comments here. To all who've commented so far: Thank you.
In a few days, if I don't forget, I'll appoint whatever the page and samples look like by then as 1.0. Leaving things pre-1.0 bugs me more now than it did back when I originally published this.
The weirdest part, looking at it five years later, is that the page shows usage of and talks about puts, while the “Best Possible” code in the zip archive uses fputs. Unless anyone can think of a reason not to use puts, I'll change the zipped “Best” example over to use it after I get it both working and failing properly.
I find keeping the semantics of puts in my working memory to be harmful. The problem is that whereas (for instance) printf(...) is essentially an abbreviation for fprintf(stdout, ...), puts adds a newline whereas fputs does _not_. This is a headache to keep track of.
The result of this is that I always use fputs to write a plain C string to a stdio handle, specifying stdout explicitly and adding newlines if needed, and I ignore puts entirely, much like I ignore gets. The convenience is not worth the subtle error-causing asymmetry and associated mnemonic pain, especially if that code may ever have to write somewhere other than stdout.
An inconvenient convenience. An excellent point, and just the sort of feedback I'd been waiting for; thank you. I'll publish the revised “Best” example shortly with fputs in place, and update the page accordingly.
We now use puts instead of printf. puts does not try to insert any values into the string, and it supplies the terminating newline (the \n you saw before) for us.
I don't see how "does not try to insert any values into the string" and "supplies the terminating newline" are not contradictory.
fputs() now returns a non-negative number (as opposed to 0) on successful completion. As a result, many tests (e.g., "fputs() == 0", "fputs() != 0") do not give the desired result. Use "fputs() != EOF" or "fputs() == EOF" to determine success or failure.
That's the price for over-engineering.