Or there is the "Heathfield answer": undefined behavior, it probably
reformats your hard disk. A useless, bullshit answer.
I cannot say from whom I've read about such a sentiment in this group
besides you, but he or she was missing advice on algorithms and style
instead of the standards' details. My answer is not targeted
specifically at you; I mean it in general. I'm new here. I'm certain you
don't care why I came here. I'll tell you anyway.
I came here (or first and foremost, c.l.c.m) because I had a specific
question about interpreting the C89 standard that in my opinion required
nit-picking, detail-obsessed "fanatics" (your word) to give a
trustworthy answer. It worked.
I believe this group (and c.l.c.m) is there for interpreting the C
standards. It's there to give advice mostly on *portability*. The only
true sources for bare language level portability are the C89 and C99
standards, and I'm very delighted to have found a place where humans are
willing and skilled enough to help with interpreting those standards.
Anything else I was curious about programming in C on my platform(s) of
choice I was able to find elsewhere on the net. I'm not saying nothing
else should appear here (heck I'm spamming this very group with my views
on SUS all the time), but hostility against the "portability approach"
is exactly missing the point. That very approach is the killer feature
of these two groups.
Re style: I seem to remember an endless flamewar about where to
initialize auto variables. It's a matter of taste.
[To participate in yet another religious debate: I personally find not
only the beginning of an identifier's scope important, but also its end.
Furthermore, I've liked the BSD kernel style's view on initialization of
auto vars. Therefore,
a) In my blocks I have a "list locals" section, then an "initialize
locals" section, then "other" statements. Some auto variables cannot be
initialized without multiple statements, and I don't like a list of
declarations (and since we're talking auto, definitions) with some
objects initialized and some not. Additionally, the SUS likes to say
thing like
The <time.h> header declares the structure timespec, which has
AT LEAST the following members:
time_t tv_sec seconds
long tv_nsec nanoseconds
(emphasis mine). With designated initializers first introduced in C99,
in C89 one cannot portably initialize such objects with an initializer
list (eg. { 1800, 0L } or just { 1800 }.) And then I rather express all
initializations as assignments instead, in one clump.
b) I try to limit the scope (and since we're talkin auto, lifetime) of
objects as narrowly as I can. I not only introduce them as late as
possible but also force them out of scope as early as possible.
{
type_a some_var;
/* compute some_var */
{
type_b some_temp_var;
/* stuff */
some_var = ... some_temp_var ...;
}
func(some_var);
}
This also facilitates the extraction of a compute_some_var(type_a *) or
similar function if needed.]
Re "reformatting the hard disk": AFAICT a user was contemplating
submitting bug reports to multiple compilers because the code he (or
she) inherited crashed on some platforms and did not on some others. It
happened due to undefined behavior. Reporting such phenomena as bugs
might have been an embarrassment for him/her, even though he/she didn't
write the code originally.
Recently, a security vulnerability was found and exploited in the Linux
kernel. The attack vector was to exploit a null pointer dereference
(which is undefined behavior). Masses of programmers came to rely on
their programs crashing with SIGSEGV in response to dereferencing a null
pointer returned by malloc() or something else, so they didn't bother to
check ("the only thing to do would be exiting/aborting anyway"). They
erred.
Undefined behavior should be taken seriously.
Listen to them speak: "Automatic variables for which there is no
explicit initializer have undefined (i.e. garbage) values". How many of
the clc "regulars" would tolerate that inexact but highly informative
parenthesis in their quest for literal exactness?
"(garbage)" is highly informative in a tutorial context, and inexact in
a reference context. I consider c.l.c(.m) to belong to the reference
kind; in the end, that's why I came here. As said above, everything else
is out there anyway. I don't claim anybody should start learning a
programming language looking at the corresponding standard, just as you
don't learn a natural language by reading the grammar and the dictionary
end to end. But once you find your way in the language, a reference
becomes invaluable.
Insisting on "obscure" details of the standard(s) reflects a painstaking
attitude in programming. C is a sharp tool, you'll cut yourself if
you're not careful. Perhaps not due to an instance of undefined behavior
in your code, but maybe because you're comfortable looking only at Linux
manual or glibc info pages instead of the SUS; and your code will break
on Solaris or OSF/1 (now Tru64) or wherever. If this sounds
condescending, it truly is not; from what I know, your C programming
experience may exceed mine a hundred times -- "you" denotes the generic
"you". Still, no matter the actual standard, details are everything in
C.
I'm only a "fanatic" because I burned myself a few times and got fed up
with it. (Not that I ceased burning myself since I became a "fanatic".)
Sorry for this stupid rant.
.... For the record, C89 says in 6.5.7 Initialization: "If an object that
has automatic storage duration is not initialized explicitly, its value
is indeterminate." 3.16 undefined behavior: "Behavior, upon use [...] of
indeterminately valued objects [...]".
C99 6.7.8 Initialization, paragraph 10: "If an object that has automatic
storage duration is not initialized explicitly, its value is
indeterminate." In C99, an indeterminate value does not necessarily
involve undefined behavior; crudely put, it's either an unspecified
(valid) value or a trap representation, and accessing or producing a trap
representation through an lvalue expression is undefined behavior,
unless the expression has character type (3.17.2, 3.17.3, 6.2.6.1).
Thus the following code is undefined behavior in C89, and unspecified in
C99 -- in my interpretation:
{
char c, d;
c = d;
}
Cheers,
lacos