That was meant to be (mostly) facetious; I suppose I should have
refrained harder.
}
You have been harping about your opinion that the C standard does not
require:
int main()
...to be equivalent to:
int main(void)
..and in fact the former causes undefined behavior.
I have yet to notice any significant number agreeing with you that C90
did, indeed, make every conforming pre-C90 program without command
line arguments undefined, despite its mandate to accept formerly
working code.
Accepting working pre-C90 code was a goal of the C90 standard, but
it's not an explicit requirement stated normatively in the standard
itself. (It would have been difficult to do so, since there was no
standard definition of pre-C90 code.) Sorry to harp about it again,
but since I've been asked:
The standard (C99 5.1.2.2.1; C90 is similar) requires main to be
defined as:
int main(void) { /* ... */ }
or as:
int main(int argc, char *argv[]) { /* ... */ }
or equivalent, or in some other implementation-defined manner. The
"or equivalent" allows for things like different names for argc and
argv, using typedefs, and using char **argv rather than char *argv[].
I argue that this:
int main() { /* ... */ }
is *not* equivalent to this:
int main(void) { /* ... */ }
Why? Because this program:
int main(void) { return 0; }
int foo(void) { return main(42); }
violates a constraint, but this program:
int main() { return 0; }
int foo(void) { return main(42); }
does not. (The latter would invoke undefined behavior of foo() were
called, but it isn't; I believe the second program is strictly
conforming.) Here the only difference between a program that violates
a constraint and one that does not is the "void" keyword in the
definition of main.
I suspect that the authors of the C90 and C99 standards did not intend
this, but it's the only conclusion I can reach by reading the actual
normative wording.
In practice, this isn't a problem. I don't know of any compiler that
doesn't treat "int main(void)", in the absence of anything that calls
main or otherwise takes its address, as equivalent to "int main()" --
which, assuming "int main()" invokes undefined behavior, is perfectly
acceptable behavior.
It may be that no significant number of people have agreed with me on
this point, but I have yet to see a convincing counterargument.
As for missing a new line on the last line of input causing undefined
behavior, chapter and verse, please, or correct your statement.
It *may* cause undefined behavior, depending on a particular
implementation-defined choice. (I didn't take the time to word my
claim more carefully; it was meant to be a throwaway line.)
C99 7.19.2p2:
A text stream is an ordered sequence of characters composed into
_lines_, each line consisting of zero or more characters plus a
terminating new-line character Whether the last line requires a
terminating new-line character is implementation-defined.
If an implementation requires the terminating new-line character, what
happens if a program doesn't provide it? The standard doesn't say, so
the behavior is undefined by omission.
For example, in an implementation where text files are structured
entities (as opposed to the simple byte sequences used on Unix and
Windows), closing a text stream without providing a terminating
new-line might leave the corresponding file in an inconsistent state,
making it impossible to open. Or the last partial line of output
might be dropped, or some arbitrary amount of trailing text might be
dropped. An implementation *could* detect this and fix it up by
adding a new-line in fclose() if the last character written was
something other than a new-line, but the standard doesn't require it.