Re: The annotated annotated annotated C standard



In article
<96af1648-bd91-43d1-a570-dbda544a4a5d@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>,
spinoza1111 <spinoza1111@xxxxxxxxx> writes
Here I shall start a review of "The Annotated Annotated C Standard" at
http://www.lysator.liu.se/c/schildt.html, the source of many of the
attacks on Schildt.

If you wanted to discuss my review of the book, it would have been
polite to at least let me know it was happening. I'm not exactly hard to
find, either on the Internet or in real life.

My article, and the resulting web page (thanks to Jutta for marking it
up into HTML) were a review of the book. They weren't written as an
attack, though they are indeed critical.

"many attacks"? I wrote the material in 1994 and edited it slightly in
1995. I don't even recall anyone mentioning it to me in the last 10
years, so I'm intrigued as to why this attack - or counter-attack if you
prefer - has happened now.

The front cover of the book shows, amongst much clutter and someone's
half-eaten muffin, page 147 of the standard. It is intriguing to note
that, not only is this the obsolete ANSI standard rather than the ISO
standard, but that it corresponds to half of page 146 in the book.

-Nilges->Tsk, tsk, clutter: meant by the illustrator (not Schildt) to
show an orientation towards the needs of the working C programmer
working with multiple nonconformant-in-the-main C compilers. Anything
at all to extend the charge ***? Anything to dehumanize? Contempt
for the body?

Amusement on my part that the cover didn't match the contents.

3.13
-Schildt->## However, this limits the total character set to 255
characters.

Actually, it limits it to UCHAR_MAX characters, which is at least 255,
but can be more. There was an opportunity here to explain what
multibyte characters actually are, but it seems to have been missed,
possibly because of the lack of space

-Nilges->This is a favorite hobby-horse of the hortatory Heathfield.

Multi-byte characters? Yes, it was at the time, because they were one of
the less-well-understood aspects of the C Standard (they probably still
are).

In reality, any C programmer who merely changes what is only a
#define, e.g., a text-replacement macro with file scope, without
auditing EACH AND EVERY LINE for character width dependent operations
such as shift and rotate is incompetent,

On the contrary, the competent C programmer either makes her code not
dependent on character width in the first place, or puts guard tests in
so that it won't compile if there is such a dependency [or she keeps the
code to herself and notes its limitations].

Pragmatically Schildt is telling students what they need
to know.

The book I reviewed is called "the Annotated C Standard", not "the
student's guide to C programming on the x86 family". The C Standard was
carefully crafted to work on a range of machines, some of which are
quite possibly beyond your imagination. One requirement that it does
*not* put on implementations is that UCHAR_MAX is 255.

It so happens that the (perhaps) commonest implementation has that
value, and that POSIX has also made that choice (after I pointed out the
implications of not doing so, as it happens), but neither of those is
what the Standard is about.

I note that your extracts omitted the following piece of the
introduction:

Many of these comments might appear to be relatively trivial. In
response to this, I can only point out that the book is commenting
on a very carefully designed document, and one that has to be read
precisely. If the annotator cannot get things right, then the book
is not just useless, but is a positive danger to those who do not
have the time to read and analyse every word of the standard. In
other contexts, such as a tutorial on C, some of the errors in this
book could be allowed to pass, but not in this.

That statement can't be repeated too often. This is a book replicating -
and then annotating - a technical standard. When you play in that game,
you get to play by its rules, and one of those rules is that every
little detail matters.

3.14
-Schildt-> An object is either a variable or a constant that resides
at a
## physical memory address.

In C, a constant does not reside in memory, (except for some string
literals) and so is not an object.

-Nilges->These types of dogmatic statements show that the speaker has
no compiler or interpreter experience

Wrong.

and is a lousy teacher to boot.

Perhaps, though the University of Cambridge was happy when I taught
computer programming, and more recently people were happy to pay large
sums of money to have me teach them.

Schildt developed a Tiny-C interpreter in 1989 and is a good teacher.

He may be - I've never had him try to teach me.

However, on the evidence of his book, he's not a good Standards person.

The standard is silent on where constants are.
[...]

True, and I accept that in implementations a constant may end up in some
kind of memory.

But *in the C Standard* it is not an object and does not reside in
memory. Since "object" is a key concept in the Standard, this matters.

5.1.1.3
The standard is clear that diagnostics are required when syntax rules
and constraints are violated, and are optional otherwise. This is not
covered at all. Instead we get the vague statement that

-Schildt-> The standard requires that a compiler issue error messages
when
## an error in the source code is encountered.

without discussing the different kinds of errors.

-Nilges->Although this is NOT an "error" at all, the purpose being to
ruin Schildt's reputation,

Nonsense. It's a *criticism* of his writing. The Standard requires
rather fewer error messages than people expect. At the time I was
writing, this was one of the major discussion points on the C Standard
and, I felt, deserved treatment.

And it is an error on Schildt's part: there are a huge number of errors
- and types of errors - in source code where the Standard does *NOT*
require that the compiler generate an error message.

it is treated as a countable error.

I was not counting errors. If I were, I would have counted every single
time he used "void main()" or assumed that a byte is 8 bits. But, since
I was writing a critical review of the book, I simply pointed it out the
first time and left it at that.

Furthermore, I freely accept that some of my criticisms were over his
choice of what to cover. That's not an error, it's a choice of the
author. I merely feel - as I have the right to - that he made the wrong
choice.

Again, I note how your extracts carefully omit my introductory
statement:

When I state that no mention is made of a topic, this indicates that
I feel that the topic is at least as important as ones that were
commented on; quite often this refers to the features of the
standard which are less easy to understand.

I am
disgusted by this. This is amateur editing by people who can't
themselves write.

PKB problem. You seem to not understand the difference between "edit"
and "review".

5.1.2.2
-Schildt-> You are therefore free to declare main() as required by
your
## program.

This statement is immediately followed by the example:
void main (void)

even though the text of the standard directly opposite states that
this is undefined. Indeed, the text I quote makes me wonder whether
Schildt believes that:
struct foo { int i; double d; } main (double argc, struct foo
argv)

is permitted !
Most of the examples in the book declare main() as void. I won't
bother to point them out individually.

-Nilges-> Everybody knows this to be unfashionable (see Stroustrup's
FAQs).

On the contrary, many of us know what the issue is and why the Standard
made the statement it does.

Your problem here is that your hero screwed up big time. Does he think
that the C90 Standard allow "void main (void)". If the answer is "yes",
then he can't read the words right in front of him. If the answer is
"no", then he is lying to his readers. Which is it?

Let me help you further. Here's the actual wording from the C90
Standard:

The function called at program startup is named main.
The implementation declares no prototype for this function.
It can be defined with no parameters:

int main(void) { /*...*/ }

or with two parameters (referred to here as argc and argv,
though any names may be used, as they are local to the
function in which they are declared):

int main(int argc, char *argv[]) { /*...*/ }

Nobody knows why it's important.

You mean that you don't know why it's important. All of us who - perhaps
through a typo - have accidentally declared main with a different type
know that there's an issue.

It is not. In practice, no
competent programmer calls main().

Irrelevant. This is about how the programmer declares main, not how she
calls it.

And while calling main is unlikely in most code, I've known situations
where it's been the right thing to do.

If it is a serious error for a
given compiler, then it should produce a diagnostic,

Perhaps it should. However, contrary to what your hero says, it isn't
required to.

or, perhaps a new
type of diagnostic: Unfashionable Code.

If you think that's a new concept, you are sadly lacking in experience,
education, or both.

-Nilges-> The lack of compassion, the lack of a sense of proportion,
and the artifact worship is the nastiest sort of geekdom at its worst.

Oh dear, you're starting to froth. You don't seem to understand the
point of a review, and you certainly don't seem to understand the
context in which the original review was written.

Even if a given set of programmers is misled by Schildt (which hasn't
been established at all) they are not held harmless "just because it's
in a book". They are responsible for interpretation as we all are:

So it's not Schildt's fault for writing a book that directly contradicts
the facts of the topic, it's the fault of his readers for not
interpreting him correctly. So when he writes "void" we should all have
realized that of course he meant "int", and when he writes "it is not an
error" (6.3.2.2) he means "it is an error".

I am enlightened. So when I wrote "this is wrong", you should have
interpreted it as "Schildt is a God and we should all bow down and
worship his every word". Of course, then you would have had no excuse
for venting your bile and would need to disappear in a puff of logic.

no
text can provide the "literal" truth...not even the Bible or Qu'ran,
and, *a fortiori*, no goddamn computer book.

True, but this one is rather further from the literal, or metaphorical,
truth than its purchasers deserved.

5.1.2.2.1
-Schildt-> Though most compilers will automatically return 0 when no
other
## return value is specified (even when main() is declared as
## void), you should not rely on this fact because it is not
## guaranteed by the standard.

Indeed it is not. If main() is declared as void, I don't know of any
compiler that will return 0. Indeed, the standard forbids it to !

-Nilges-> A non-error is counted as an error. You people make me sick
to my stomach and want to throw up.

Don't let me stop you. See if you can hit the muffin on the cover.

There's an error and a non-error in Schildt's words. I freely admit the
non-error - like I said, it's a review, not a count of errors - and
point out the error. And, despite all your quibbling, the error is
blatant: the concept "return 0" makes no sense for a void function.

-Nilges-> And if we must quibble in the style of "CDW Feather",

Why the quotes, "Nilges"? It's my name or, to be precise, my initials
and surname. My full name is Clive Douglas Woon Feather. It's the name
on my passport (though not my birth certificate) and it (or contractions
thereof) is what I'm known as.

the
compiler doesn't "return" jack ***.

True. Well, false in that the compiler on (say) a Unix system returns a
status code, but that is nit-picking. The compiler generates code that
returns 0, or doesn't, as the case may be.

There's that lesson about the
beam in thy own eye.

True. Very true.

But there again, it's your hero who wrote "the compiler returns 0" - I
simply copied him and didn't bother to pick that particular nit.

I may have a mote or two in my eye, but it's the pair of you that have
several beams.

-Nilges-> Schildt gets it mostly right.

False both in this instance and in a lot of other places (and I note how
many of my criticisms you seem to have no response to).

You get the "compiler" doing
something at run time.

You get it doing something, yes. Unfortunately, it tends to be something
different to what Schildt says it will.

Show some class.

This isn't C++.

5.1.2.3
This section is often called the "as if" rule, because it says that an
implementation may do anything providing that the effect is "as if"
the exact wording of the standard was followed. This is almost
completely ignored in favour of explaining "side effect" and
"automatic storage".

-Nilges-> A matter of style and literary criticism is counted as an
error by people who cannot write. You people make me sick to my
stomach and want to throw up.

We still aren't stopping you.

You still don't seem to know the difference between "error" and
"criticism". I'll repeat:

When I state that no mention is made of a topic, this indicates that
I feel that the topic is at least as important as ones that were
commented on;

I feel that a book commenting on the Standard - as opposed to one
written for novices - would do better to explain the "as if" rule than
to repeat elementary material about automatic storage.

5.2.1.2
## Therefore, a multibyte character is a character that requires
## more than one byte.

Ignoring the fact that "character" and "byte" are synonymous in the
standard (something that is not mentioned in the annotations), the
definition of multibyte character is clear that it *does* include
single byte characters.

-Nilges-> A quibble is counted as an error..

It's not a quibble, it's a non-trivial point, particularly if you want
to use C for international applications.

And if "character" and
"byte" are synonymous in the standard, then C is useless for
international applications, and is not worth a standard.

<------------------------- you
the point -------------------------->

The C Standard uses non-intuitive terminology in this area. A proper
annotation would explain what the terms mean and how to use C to write
internationalised code. A proper annotation would not say something that
is different to what the actual Standard says.

I could explain all these terms to you. Unfortunately, while I have the
5 minutes that would take to explain them to the average reader of this
newsgroup, I don't have the month it will take in your case.

## First, the null character may not be used except in the first
## byte of a multibyte sequence.

I read this as meaning that the multibyte character <00><94> is legal
while the multibyte character <94><00> is not.
[...]
-Nilges->A world-class MISTAKE (the FAILURE to support Nuls as
ordinary characters) in C is used to beat the Herbster guy.

"The Herbster guy" was sloppy. Something you have no hesitation in
accusing me of.

5.2.3
-Schildt-> In other words, one copy of a library function in memory
may
## not be used by two or more currently executing programs.

This is blatant nonsense - on most Unix systems, if the same program
is executing several times, all the code is shared by both processes.
Indeed, many go further and share one copy of the standard C library
among every process on the system.
What this section of the standard is talking about is re-entrancy.
The functions in the library are not re-entrant, and so may not be
called from within themselves. For example:
[...]
-Nilges->The attackers of Schildt have themselves ignorantly misused
"re-entrancy". "Re-entrancy" does not mean "can be used recursively"

True.

although it implies recursive callability.

Which is why I wrote "and so". You seem not to understand Boolean logic
among all your other failings.

It means that the re-
entrant code does not include variables that not on the stack but
[...]

No. That may be one attribute of one style of re-entrant programming,
but the term doesn't mean just that.

And I meant what I wrote: the functions in the library are not
re-entrant. Which is absolutely *nothing* to do with:

-Schildt-> In other words, one copy of a library function in memory
may
## not be used by two or more currently executing programs.

Since the Standard doesn't even have the concept of "two or more
currently executing programs", a comment like that doesn't belong in the
book without a lot of explanation (which it didn't get). And it remains
completely false: even Windows can cope with the idea of two programs
executing the same block of code at the same time, even when that code
is not re-entrant.

-Nilges->In fact, the use of "re-entrant" by CDW Feather

Oh good, we've lost the quotes.

shows a
programming psychology dating to the IBM mainframe era, in which
procedures were "re-entrant" only by accident, and everybody went
"oooooo re-entrant".

I still see plenty of procedures that aren't re-entrant. It's not hard
to make something re-entrant, but nor is it trivial.

It's not a proper computer science term, it's a
programming term which reveals ignorance!

"not a proper computer science term". Hmm, I must tell all the people
who taught me back when I got my degree in computer science.

The association of the procedure with state is something that has to
be discovered by examining a file. Having to know this about "library"
function completely violates common programming sense, because a
"library" needs to be a black box.

That's close to being a reasonable criticism of the C Standard. It would
have been far better if the library was re-entrant and had no hidden
state. Unfortunately, that wasn't an option for various reasons.

-Nilges->Herb is right, depending on multiple nonconformant and
incompatible implementations, as a matter of humane teaching of a
mistake.

I can't even parse this.

This was the failure by Kernighan and Ritchie to come to
terms with, and evolve rather than steal, Algol and the stack, and
thereby to enable code that would keep state in overly global
variables with file scope.

You seem to think that K&R should have made major extensions to
programming language theory - though I'd be interested to actually see
your "evolutions" of Algol - rather than write a systems programming
language which could be compiled efficiently in the environment they
were working in.

But, there again, I suspect you'd collapse into a little puddle if you
were faced with the prospect of creating a working compiler for a system
with 40kB of RAM or with a 5-and-a-half bit byte.

-Nilges-> Herb gives the safest possible advice

He doesn't give any advice at all. He just spouts nonsense about two
consecutive programs.

In fact, this is a major defect of nearly
all non-OO languages: it is impossible to tell whether a library
function has state,

On the contrary, you merely need to read the language standard.

whereas this is made clear, in C Sharp, by the use
of the static keyword as part of its public contract...which forces
the programmer to keep the contract, not only with the compiler, but
also, and more importantly, with the user.

Oh? You think I can't write a stateful function with the static keyword?
Your imagination is sadly lacking.

-Nilges-> You cannot malloc() inside of malloc() inside of a signal
handler. This is obscene,

It's annoying, I agree. I can see why the choice was made, though.

but it is implied by what Herb says.

No it isn't, since we're talking about a *single* executing program, not
"two or more".

And
what stinks even more is that the programmer has to "know" about an
error.

Curiously enough, most languages require the programmer to "know" about
their features and limitations.

This is the end of part One as I walk through the annotated-annotated
C standard, which in reality is an unethical and uncollegial attack on
a computer author, probably mounted for commercial gain, both to
promote a competing book,

"unethical"? Another PKB problem, I see. You're the one breaching
copyright (and don't give me guff about "fair use", because that doesn't
apply to the quantities you're posting). However, since "de minimis"
applies, I'll probably just have a laugh with Yahoo!'s customer
compliance manager when I have lunch with her on Monday.

"uncollegial"? What college would that be? I'm 99.4% certain that
Herbert Schildt never attended Trinity College. I would also hope he is
ethical enough to accept criticism when it's deserved.

"commercial gain" "to promote a competing book"? I've never written a
book in my life. I've written some articles about the C Standard that
got published (and I got paid for). But they were commissioned by people
who knew my knowledge of C and the C Standard, not because of my review
of Schildt.

But my review was certainly not written for commercial gain or even for
money (though, IIRC, a couple of people have bought me drinks on the
strength of it). It was written as a public service after various
comments had been made about the book in comp.std.c. Oh, and to while
away a wet autumn Saturday in Santa Cruz.

and to maintain the illusion that
"standardizing C will bring it back to life".

Well, it did do so.

It is written by people

Why "people"? I wrote it on my own.

who unlike Herb don't know what goes on in sufficient detail at
compile and run time,

Can you explain the difference between a static chain and a display, and
indicate which would be more suitable for a given architecture? Can you
explain the difference between LR(1) and LALR(1) and the implications of
using one rather than the other? How about Iron's Diagram?

Nobody expects a Spanish Inquisition,

I don't see why not, these days. But then I'm the one sitting in the
comfy chair.

I shall continue to post extensions this "annotated annotated
annotated" document because at this point, I am sick to my stomach at
the treatment of Schildt and I want to throw up.

That's three times. Since what you've told us three times doesn't seem
to be true in your case, perhaps you should go out and buy an emetic.

It's par for the
course in a field in which students are forced to learn their elder's
mistakes as if those mistakes were Holy Writ,

<falls about laughing> You *clearly* don't know me.

--
Clive D.W. Feather | Home: <clive@xxxxxxxxxx>
Tel: +44 20 8495 6138 (work) | Web: <http://www.davros.org>
Fax: +44 870 051 9937 | Work: <clive@xxxxxxxxx>
Please reply to the Reply-To address, which is: <clive@xxxxxxxxxx>
.