Thread View: comp.lang.c.moderated
11 messages
11 total messages
Started by J. Blustein
Tue, 02 Apr 1996 01:55
Annotations on K&R II
Author: J. Blustein
Date: Tue, 02 Apr 1996 01:55
Date: Tue, 02 Apr 1996 01:55
183 lines
9253 bytes
9253 bytes
This summer, I reread the New Testament and started making notes in
the margin. I don't normally mark up books, but I thought it worthwhile
this time. I think that other C programmers, particularly new ones, will
find my list of annotations useful. I put a copy on the WWW at
http://www.csd.uwo.ca/%7ejamie/.Refs/.Footnotes/C-annotes.html but that
won't be around forever. This posting is my attempt to get the list out to
a greater audience and perhaps even have it preserved somewhere.
ANNOTATIONS ON K&R II
Purpose
Upon re-reading The C Programming Language (second edition) by
Brian W. Kernighan and Dennis M. Ritchie (aka K&R II) I was surprised
find out how much richer it is than I had remembered. I took the
uncharacteristic step of writing notes in the margins of my copy. Some
of those notes are reproduced below in the hopes that others will find
them helpful too.
I don't want to give the impression that K&R II should replace the
ISO Standard or the ANSI Rationale. I use K&R II as an introduction
and tutorial to the C language. Experienced C programmers will find
Harbison and Steele's C: A Reference Manual a better reference work
(in my opinion, of course). The Standard is, as its title implies, the
definition of the modern C language. Harbison and Steele provide
descriptions of both ISO/ANSI and pre-ANSI C, by the way.
THE ANNOTATIONS
I've listed my annotations in three parts: clarifications,
cross-references and scattered discussions. Also, I keep a very short
list of so-called quick-references below.
Clarifications
p. 6 main() requires a return (see p. 26)
p. 9 comments do not nest (see p. 34)
p. 90 ## and # are used during macro expansion only.
The comp.lang.c FAQL has something to say about
this point, see question 11.17.
pp. 94, 103, 120 void * cannot hold function pointers. For
further clarification within K&R II see
Sections A6.8 (Pointers to Void on p. 199), A.4
(Meaning of Identifiers on p. 195) and A.5
(Objects and Lvalues on p. 197).
p. 135 As the text states: sizeof *x is the size of the
pointer not the x being pointed to.
p. 143 I think that a user supplied definition of
strdup() (which is not in the standard library
by the way) would violate the ISO standard for
function names. Steve Summit wrote about this
in question 1.29 (pp. 23-26) of C
Programming FAQs.
p. 159 I find the statement that `an array name is a
pointer' misleading. See p. 99 for the details.
p. 119 Note that: 1) char * is not the same as void *
and 2) this qsort() is not necessarily the same
as the standard library's. (I got these points
from a comment on p. 229 (question 13.8) of
Steve Summit's C Programming FAQs.)
p. 163 Also, in my experience, stderr is unbuffered.
p. 183 <sys/types.h> does not define size_t. It is
defined in <stddef.h> (pp. 260-1).
p. 255 tm_sec: there can be as many as 2 leap seconds
p. 257 %S: there can be as many as 2 leap seconds
I found the errata notices helpful too. (See
http://www.csd.uwo.ca/%7ejamie/.Refs/.Footnotes/K%26RII-errata.html for
the January 1991, June and July 1992 versions).
Cross-references
I've included references to expanded definitions that appear later
in the text. My copy also has exact page numbers for many of the
cross-references by section, but there is little point to include those
here.
p. 26 The conventional interpretation of the return
statement appears at the top of p. 164.
p. 33 See extern declarations below
p. 40 The definition of static is on p. 83
p. 40 variable initialization is dealt with on p. 85
p. 42 NULL is zero (see p. 102)
p. 48 (Section 2.9: Bitwise Operators)
see also Section 6.9 (Bit-fields) on
pp. 149-150
p. 48 There is an example of operator precedence on
p. 52 (Section 2.12)
p. 63 A different swap appears on p. 96
p. 83 (Section 4.7: Register Variables)
Even though the compiler is free to ignore the
declaration register variables can be used as
documentation that the variables will be
heavily used and that its address will not be
computed, e.g. the & operator will not be
applied to them.
p. 77 See `extern declarations' (in `Scattered
Discussions', below)
p. 80 See extern declarations, below
pp. 91, 103 sizeof is explained on p. 135
p. 96 Compare this swap with pp. 62-3 and p. 88
p. 101 static variables are defined on p. 83
p. 57 (Section 5.7 Multi-dimensional Arrays)
See also Section A.6.2 (Array Declarators on
pp. 216 - 7)
p. 165 register declaration introduced on p. 83
p. 174 Section 7.6:Error Handling -- Stderr and Exit is
on pp. 163-4
p. 174 Section 7.3:Variable-length Argument Lists is on
pp. 155-6
Scattered Discussions
extern declarations
introduced on p. 33
example on p. 77
additional discussion on p. 80 (Section 4.4)
Quick References
Below are some notes I use myself as a mini index.
Array bounds p. 100
Arrays are row major (final dimension varies fastest)
p. 112
Boolean values (0 == FALSE)
p. 42
Brace style p. 10
printf() string precision examples
p.154
See also
My list of recommended programming books is at
http://www.csd.uwo.ca/%7ejamie/.Refs/tech-books.html. All of the books
referenced to here are described in greater detail there. Bibliographic
references for them are also available from the comp.lang.c FAQ list.
Document details
Last updated by J. Blustein on 30 March 1996. This version created
with the help of the CERN line-mode browser version 4.0D on 1 April
1996.
This document is copyright by its author, J. Blustein <jamie@uwo.ca>.
The author grants permission for free distribution of this document.
--
Jamie Blustein `Did you say "knives"?'
<jamie@uwo.ca> `*Rotating* knives, yes.'
Re: Annotations on K&R II
Author: Kurt Watzka
Date: Tue, 02 Apr 1996 12:37
Date: Tue, 02 Apr 1996 12:37
29 lines
1281 bytes
1281 bytes
jamie@csd.uwo.ca (J. Blustein) writes:
> ANNOTATIONS ON K&R II
>
> Clarifications
>
> p. 6 main() requires a return (see p. 26)
How about "main() without an explicit return returns an undefined value"?
> p. 135 As the text states: sizeof *x is the size of the
> pointer not the x being pointed to.
Do they write that? Sorry, I don't have K&R 2 at hand right now, but
this is _not_ true. Consider:
char (* x)[20];
char *y;
"sizeof(*x)" is the size of an array of 20 chars, not the size of
a pointer to such.
"sizeof(*y)" is 1 even on machines where "sizeof(char *)" is not
equal to 1.
Kurt
--
| Kurt Watzka Phone : +49-89-2180-6254
| watzka@stat.uni-muenchen.de
Re: Annotations on K&R II
Author: J. Blustein
Date: Tue, 02 Apr 1996 12:37
Date: Tue, 02 Apr 1996 12:37
19 lines
1264 bytes
1264 bytes
In article <4jq1eq$a3c@solutions.solon.com> J. Blustein <jamie@uwo.ca> wrote:
> Clarifications
>
> p. 6 main() requires a return (see p. 26)
I should have written that main() should have a return. I've also
found parts of page 164 useful here.
> Cross-references
[...]
> p. 42 NULL is zero (see p. 102)
That would make more sense as `NULL is equivalent to zero *in this
context*'.
Thanks to Peter Seebach for pointing out my over-zealousness about
main()'s return.
--
Jamie Blustein `Did you say "knives"?'
<jamie@uwo.ca> `*Rotating* knives, yes.'
Re: Annotations on K&R II
Author: Jerry Coffin
Date: Tue, 02 Apr 1996 12:38
Date: Tue, 02 Apr 1996 12:38
40 lines
2271 bytes
2271 bytes
In article <4jq1eq$a3c@solutions.solon.com>, jamie@csd.uwo.ca says...
[ ... ]
> ANNOTATIONS ON K&R II
> p. 135 As the text states: sizeof *x is the size of the
> pointer not the x being pointed to.
I think this bears a bit of clarification: given a definition something like:
something *x;
sizeof(*x);
does NOT give the size of a pointer at all, it gives the size of a `something'
I think you're trying to say that it doesn't give the size of the block
actually pointed to by `x', which is also true.
> p. 119 Note that: 1) char * is not the same as void *
> and 2) this qsort() is not necessarily the same
> as the standard library's. (I got these points
> from a comment on p. 229 (question 13.8) of
> Steve Summit's C Programming FAQs.)
While `char *' and `void *' are not the same, they are required to have the
same representation. (The general idea seems to be that if you pass one in
place of the other, it probably shouldn't cause a problem, but they never
quite state that explicitly. I presume this was an attempt at enforcing
compatibility with older libraries that expected a `char *' where a `void *'
is now indicated.)
> p. 183 <sys/types.h> does not define size_t. It is
> defined in <stddef.h> (pp. 260-1).
If memory serves, under POSIX, sys/types.h is required to define size_t as
well. sys/* are NOT defined by the C standard at all. size_t is required to
be defined in string.h, stdlib.h and time.h in addition to stddef.h, for what
little it may be worth.
Later,
Jerry.
Re: Annotations on K&R II
Author: J. Blustein
Date: Wed, 03 Apr 1996 13:10
Date: Wed, 03 Apr 1996 13:10
16 lines
1326 bytes
1326 bytes
In article <4jr727$h6o@solutions.solon.com> Kurt Watzka
<watzka@stat.uni-muenchen.de> wrote:
>jamie@csd.uwo.ca (J. Blustein) writes:
[...]
>> p. 135 As the text states: sizeof *x is the size of the
>> pointer not the x being pointed to.
>
>Do they write that? Sorry, I don't have K&R 2 at hand right now, but
>this is _not_ true. Consider:
That's right. I think my note was based on a misunderstanding of
something else I read. I have changed the annotation to `sizeof is better
defined in A7.4.8 on page 204'.
--
Jamie Blustein `Did you say "knives"?'
<jamie@uwo.ca> `*Rotating* knives, yes.'
Re: Annotations on K&R II
Author: Richard A. O'Keefe
Date: Wed, 03 Apr 1996 13:10
Date: Wed, 03 Apr 1996 13:10
17 lines
1325 bytes
1325 bytes
jamie@csd.uwo.ca (J. Blustein) writes: > p. 255 tm_sec: there can be as many as 2 leap seconds > > p. 257 %S: there can be as many as 2 leap seconds > More precisely: the C standards committee misunderstood the international time standards and allowed for two leap seconds in the same minute. There _can_ be two leap seconds in the same _year_, but not in the same _minute_. I've not yet had the good fortune to come across a C implementation that bothers with leap seconds (if I've understood POSIX.1, a UNIX implementation _mustn't_ get leap seconds right), so it's not that much of a problem. -- Result of state election = 50% Victorians didn't get MP of their choice. Richard A. O'Keefe; http://www.cs.rmit.edu.au/~ok; RMIT Comp.Sci.
Re: Annotations on K&R II
Author: Konrad Schwarz
Date: Thu, 04 Apr 1996 00:56
Date: Thu, 04 Apr 1996 00:56
23 lines
1664 bytes
1664 bytes
In article <4jr73o$h87@solutions.solon.com>, jcoffin@rmii.com (Jerry Coffin) writes: |> While `char *' and `void *' are not the same, they are required to have the |> same representation. (The general idea seems to be that if you pass one in |> place of the other, it probably shouldn't cause a problem, but they never |> quite state that explicitly. I presume this was an attempt at enforcing |> compatibility with older libraries that expected a `char *' where a `void *' |> is now indicated.) My understanding is that a conversion to a (void *) followed by a conversion to the original pointer type is the identity mapping; in other words, the mapping a C compilers uses between (void *) and any other pointer type is bijective. I don't know what you mean with representation; note however that T1 *p; *(T2 **) &p == (T2 *) p is not necessarily true, even, I think, if T1 or T2 is void. This is the reason why casting the comparison function argument of qsort to a function of two void pointers even if the actual argument is a function of two pointers to non-void is non-conforming, since the compiler now has no place to insert the pointer-conversion code. Konrad Schwarz
Re: Annotations on K&R II
Author: telnet user
Date: Fri, 05 Apr 1996 00:38
Date: Fri, 05 Apr 1996 00:38
58 lines
2904 bytes
2904 bytes
Konrad Schwarz (schwarz@mips.complang.tuwien.ac.at) wrote:
: My understanding is that a conversion to a (void *) followed by a conversion
: to the original pointer type is the identity mapping; in other words, the mapping
: a C compilers uses between (void *) and any other pointer type is bijective.
: I don't know what you mean with representation; note however that
: T1 *p;
: *(T2 **) &p == (T2 *) p
: is not necessarily true, even, I think, if T1 or T2 is void.
: This is the reason why casting the comparison function argument
: of qsort to a function of two void pointers even if the actual argument
: is a function of two pointers to non-void is non-conforming, since the
: compiler now has no place to insert the pointer-conversion code.
To be a bit more explicit on that point, since it's a bit subtle:
This isn't guaranteed to work (though it is how many people do it):
---
int compare(const int *x, const int *y) {
return *x - *y;
}
...
/* This next line casts (int (*)(const int *, const int *)) to
* (int (*)(const void *, const void *))
* which is _not_ the same as casting (void *) to (int *).
* The compiler can't conceivably insert conversion code here, because the
* function isn't being called, and there are no args to 'convert'.
* qsort() can't do the conversion, because the original type has been
* 'casted away' already.
*/
qsort(base, num, sizeof(int), (int (*)(const void *, const void *))compare);
---
As opposed to the following:
---
int compare (const void *px, const void *py) {
int x = *(int*)px; /* these are (void*)->(int*) casts, which are */
int y = *(int*)py; /* guaranteed to work. If the pointers have */
/* different formats, the compiler _must_ insert */
/* conversion code here */
return x - y;
}
...
/* Note no cast needed here, since compare is already of the right
type */
qsort(base, num, sizeof(int), compare);
---
---------------------------------------------------------------------------
Tim Hollebeek | Disclaimer :=> Everything above is a true statement,
Electron Psychologist | for sufficiently false values of true.
Princeton University | email: tim@wfn-shop.princeton.edu
----------------------| http://wfn-shop.princeton.edu/~tim (NEW! IMPROVED!)
Re: Annotations on K&R II
Author: Claude Quezel
Date: Fri, 05 Apr 1996 00:39
Date: Fri, 05 Apr 1996 00:39
41 lines
1782 bytes
1782 bytes
Konrad Schwarz wrote:
[stuff left out]
> This is the reason why casting the comparison function argument
> of qsort to a function of two void pointers even if the actual argument
> is a function of two pointers to non-void is non-conforming, since the
> compiler now has no place to insert the pointer-conversion code.
I am not sure I understand this. Is that this code is illegal?
[Well, the //'s are illegal, because they're a syntax error... -mod]
int comp(const type* p1, const type* p2) {
// logic here
}
type array[size];
qsort(array, sizeof(array)/sizeof(array[0]), sizeof(array[0]),
(int(*)(const void*, const void*)) comp);
and that this is?
int comp(const void* p1, const void* p2) {
// logic here with ((type*) p1) and ((type*) p2)
}
type array[size];
qsort(array, sizeof(array)/sizeof(array[0]), sizeof(array[0]), comp);
------------------------------------------------------------------
" When I use MS Word 6.0 on a PC running windows 3.1 and DOS 6.0
and write a normal plain english letter, The Tools/Languages ...
option never works. It never succeeded in translating ( in any
languages). This is a serious bug. "
------------------------------------------------------------------
Re: Annotations on K&R II
Author: Henning Makholm
Date: Thu, 11 Apr 1996 18:54
Date: Thu, 11 Apr 1996 18:54
15 lines
1247 bytes
1247 bytes
schwarz@mips.complang.tuwien.ac.at (Konrad Schwarz) writes: >My understanding is that a conversion to a (void *) followed by a conversion >to the original pointer type is the identity mapping; in other words, the >mapping a C compilers uses between (void *) and any other pointer type is >bijective. It is not necessarily, the mapping from (useful*) to (void*) is not required to be surjective, and the mapping from (void*) to (useful*) is not required to be injective, except when restricted to the set of (void*)s that points to objects with suitable alignment for useful's. -- Henning Makholm - math and CS student - University of Copenhagen makholm@diku.dk - http://www.diku.dk/students/makholm - fido 2:235/224.92
Re: Annotations on K&R II
Author: ct
Date: Thu, 11 Apr 1996 23:51
Date: Thu, 11 Apr 1996 23:51
23 lines
1680 bytes
1680 bytes
In article <4k60bd$aa1@solutions.solon.com>, Jerry Coffin <jcoffin@rmii.com> wrote: >In article <4jv6o8$coj@solutions.solon.com>, >schwarz@mips.complang.tuwien.ac.at says... >> >> My understanding is that a conversion to a (void *) followed by a conversion >> to the original pointer type is the identity mapping; in other words, the >> mapping a C compilers uses between (void *) and any other pointer type is >> bijective. > >Hmm...I'm not sure what "bijective" means (my dictionary doesn't include it) >the basic idea here seems to be correct: "A pointer to any incomplete or >object type may be converted to a pointer to void and back again; the result >shall compare equal to the original pointer." ($6.2.2.3) Actually, he's mistaken about the "bijective" bit, the map is only "injective". Bijective means the mapping is two-way on both domains, ie a cast from a (Type *) to a (void *) can be cast back (true) _and_ that a cast from a (void *) to a (Type *) can be cast back (generally false). (Since the mapping from (Type *) to (void *) is injective, it follows that the mapping from (void *) to (Type *) is surjective.) regards, ct
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads