This document was originally written as a morning's work in mid-March of 1995. The idea came from a vague idea I had about "correcting" the FAQ posting that year. When I started thinking of questions to which I could provide "corrected" answers, I realized I could do quite a lot of them - almost enough to do my own FAQ! The first section I wrote was "Null Statements", all of the others came later. However, perhaps 80% of the text you see here was, with minor alterations, written that morning.

You'll notice that the IAQ is much shorter, and perhaps less informative, than the real FAQ. This is largely a result of laziness, but I don't think there's as much funny stuff to be written; already, this suffers from an excessive reuse of jokes.

These annotations are intended to highlight and explain the jokes. You see, some people don't get them. One person corrected "errors" (some of them, in fact, were factually correct!) up through Chapter 7, pointing out at one point "you would have done better to leave this as a humorous non-answer"; apparently, the fact that they're all humorous non-answers had escaped him.

Intro Annotations:

Starting from "Certain Topics", this is just word-similarity parody of the comp.lang.c FAQ.

Table of Contents:

Nothing to see but a link farm. Move along, move along.

Section 1: Declarations and Initializations

Several of the jokes in this section are snide comments about the horribly stupid rules people use, and even write up in books, for how to choose data types, and some of the misconceptions people have about them.


Of course, the joke here is that the encoding for the character set (thus, the representation of character constants such as 'i') has nothing to do with the location of objects with a given name. This question has garnered more "corrections" than any other; typically, it's the first really obviously wrong answer that people see, but if they're going to see a funny answer and not get the joke, this is the one. Of course, the conclusion reached is correct - outside of structures, there's no ordering at all to variable declarations, and even inside structures, there can be arbitrary padding between members.


The rule proposed is precisely backwards; definitions are what conflict with each other, while multiple compatible declarations are allowed. Most programmers like being able to include a header once in every module, at the very least - which is what's prevented by having multiple definitions.


Subtle point: In many implementations, the program will compile without errors - it's only the "link" phase (translation phase 8, to the pedants) which fails when no object named bar can be found. The remark about assigning bar a value is a reference to the difference between a declaration (such as "int bar;"), which is compatible with another, external, definition, and a definition (such as "int bar = 5;") which reserves storage.


Several jokes in here. The first is the one about Microsoft inventing C. Microsoft is often credited with inventions they had nothing to do with; I just wanted to be a joiner. I once posted a URL for this question in part of a Usenet discussion, along with a paragraph (in the Usenet post) crediting Microsoft with the invention of "the separation of Church and State". Despite this, I got angry corrections from people who didn't like Microsoft.

The code is subtly wrong in many ways. Apart from the subtle type mismatch (printf's first argument is const char *), the second example is completely wrong; a function name without ()'s to indicate calling is just an expression, which is discarded. This is the real reason the function pointer is only called through in the first example. The comment about ls is completely irrelevant.


This is obviously complete nonsense, although it would likely work on some system somewhere. Of course, it would lead to a huge amount of casting which shouldn't be necessary at all. A more traditional solution would be to separate the typedef out from the struct declaration, and put the typedef first, or alternatively, to name the struct and spell its name out in the declaration of the pointer-to-next-item.


Well, actually, regular ints can be entered using hexadecimal notation, and the example given shows octal (but is correct, because after all, octal 07 and hex 0x7 are the same value.)


For about two years, there was an imbalance in the huge expression; I had a square bracket matched with a parens. One of the "corrections" I got was a suggestion that this huge expression would be more readable if I used typedefs to build it. Obviously, this construction is completely wrong; it's done wrong-way-out, and then some. The "mirrors" comment is just a remark about the constant abuse of the phrase "declaration reflects use". (Which is actually a fairly accurate model; the idea is that, if I declare "int *ip", that "*ip" will have type "int". Thus, declaration ("*ip") reflects use ("*ip").)

Section 2: Structures, Unions, and Enumerations

This section has no cohesive structure; it's pretty much just a collection of really bad answers to questions from the real FAQ.


Obviously, Ritchie developed C long before he wrote the book, and he worked at Bell Labs all along. The "video game developer" is a reference to the story that Unix evolved from a "space war" game developed by Thompson.


Once again, just plain nonsense. Of course, the caveat is correct for some systems, by sheer coincidence. Structs passed on the stack were once fairly risky because some systems had very limited stack space.


The idea is that, since all output occurs "as if by successive calls to fputc", and putchar is really very similar to fputc... Of course, this is nonsense. The line about the sign bits is just noise; I wasn't referring to anything in particular, except perhaps the general paranoia about signed types that I tend to have.


A surprisingly good rule, for how stupid it is. This is a side effect of the "all the world's a 32-bit machine" fallacy.


The gimmick here (related to 2.6's 4-bytes-per-object joke) is that the size of the union will almost always be the size of the largest member (8 bytes is common on many systems), which happens to be the sum of the logical sizes of the other members. At least one reader pointed out that this code could never be expected to work; most astute.


Mr. Reagan (U.S. President, 1980-1988) fired a number of air traffic controllers who went on strike (which their contracts, plausibly, prohibited).


C9X actually offers a way to do this, with the very similar (struct foo) { 3 }.

Section 3: Expressions

Of course, most of these are jokes about the meaning of undefined behavior.


The point here is that the comma operator creates sequence points, and, because it has such a low precedence, it tends to have very powerful control over otherwise confusing expressions. Of course, it makes them just as confusing... but that's okay.

Section 4: Null Statements

This section is mostly phrasing-similarity games with the FAQ's section on null pointers. Null statements are probably nearly as misunderstood, simply because they're rarely used.


The line about the FDA refers to the "side-effects" of drugs; a completely different meaning of "side-effects".


"All bits zero" is a reference to the common belief that a "null pointer" is a pointer with a machine representation consisting entirely of zero bits.


I can't resist a chance to dig at C++'s vast collection of features which probably wouldn't have survived except that someone had existing code...


More utter nonsense derived from common misunderstandings. In particular, it's not clear what "segment bits" are supposed to be, and it doesn't matter whether or not there's a stray value in a statement that doesn't do anything.


If you follow the first two rules, you'll probably be okay. The line about "the author of the FAQ, or the moderator of the group" refers to the fact that I was posting this to comp.lang.c.moderated, which I moderate. (Steve Summit, the author of the original FAQ, is one of my co-moderators) Emily Postnews is the (fictional) author of a delightful guide to netiquette; no one listens to her (which may be just as well, as all of her advice is intended to be taken as sarcasm).

Section 5: Arrays and Pointers

5.1, 5.2

This is just a parody of the question about "char *a" and "char a[6]" in the real FAQ; of course, the two declarations are incompatible.


In fact, the reason typically given is that arrays aren't really quite objects in C, and they're often described as "second-class objects". The reference to Marxism is irrelevant, at best.


When I started annotating this, this was question 5.6; I have no idea what happened to 5.5. Anyway, the material is, of course, a joke. The real reason is that the function's parameter is a pointer, not an array; this looks silly, but it's how the language was built.


In other words, "some people will say anything".


First, a joke about the surprisingly limited character set (yes, 'f' really is in the standard minimum character set), then a remark about the non-existant, but often described, "equivalence" of arrays and pointers. The "equivalence" is that, since "i[a]" really means "*(a+i)", and addition is commutative, this is equivalent to "*(i+a)", which could also be spelled "a[i]".


The code provided does, in fact, "read" the numbers zero through 99 into the array. The expression "(scanf, ("%d", i))" is really an abuse of the comma operator; the values of the string literal, and of the name "scanf" (which, since it's not a function call, decays into a pointer to the function of the same name) are discarded, so really, this is just a loop of "a[i] = i". The reason to include <stdio.h> is that, without it, there will be no prototype for scanf in scope, and that will make the reference to the name invalid.

Section 6: Memory Allocation


Of course, even if the semicolon weren't missing, it still wouldn't work, because no space is allocated for the data stored by gets, and even if it were, gets would be able to overrun that space.


This is nonsense, of course; the casts are historical from when char * was the closest thing C had to a generic pointer type.


Part of the joke is swapping nybbles, when endianness normally affects the order of bytes within larger words.

Section 7: Characters and Strings


One of the complicated tricks would be writing "i = c;".

Section 8: Boolean Expressions and Variables


This is a reference to a wonderful stand-up comedy routine about metaphysics. The same routine was the origin of the oft-repeated "Yes, fish think, but not fast enough."

Section 9: C Preprocessor


Of course, they don't. It's just a joke about the "it worked here, it must be standard" attitude one sees from some newbies.

Section 10: ANSI C


A lot of readers in comp.lang.c have been known to flame Herbert Schildt (who is an observing member of the committee) for his books on C, which frequently contradict the standard.


Of course, it was because of the specialized needs of certain committee members, but not like that.


Zork references.


Actually, it's a hack some compilers have to indicate that a file should not be re-processed, even if a series of #includes would indicate that it should be seen twice - but this is a good way to point out the complete impossibility of relying on portable behavior from a pragma.

Section 11: Stdio


The line about "fast printf" was a reference to the common belief that "fgrep" (fixed grep) is "fast grep".


I felt that the document needed at least one moderately vulgar joke. :)


Pretending that the problem is the return key, not the need to wait for a signal than input is complete.


More Zork references.

Section 12: Library Subroutines


Another text adventure, this time, Colossal Cave Adventure.

Section 13: Floating Point


Many early Pentiums had a floating point bug.

Section 16: Strange Problems


A general comment on the importance of explaining what you think the problem is.

Section 18: System Dependencies


Whiteouts are a way for a filesystem mounted "over" another filesystem to indicate that there is no file of a given name. This is pretty arcane, and totally irrelevant.

Section 19: Miscellaneous


In other words, "yes".


The #log% is a reference to the RCS behavior of putting logs in places where it sees $log$. At least on my keyboards, the punctuation used is close, but not close enough. The reference to 1 Kings 7:23 is one of the places where particularly crazy people have gotten the idea that pi is exactly 3. (In fact, the numbers given are clearly only to one significant figure, and pi, to one significant figure, is 3.)

Of course, the main point is that a math header will likely be so dependant on the system as to make it irrelevant to anyone else. Same with any other header, really.


What scares me most is that people have made it as far as Section 7 or so correcting "errors". Many of the "corrections" I've gotten over the years were actually less accurate than the material "corrected".