🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

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
#2458
Author: J. Blustein
Date: Tue, 02 Apr 1996 01:55
183 lines
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
#2466
Author: Kurt Watzka
Date: Tue, 02 Apr 1996 12:37
29 lines
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
#2467
Author: J. Blustein
Date: Tue, 02 Apr 1996 12:37
19 lines
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
#2468
Author: Jerry Coffin
Date: Tue, 02 Apr 1996 12:38
40 lines
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
#2474
Author: J. Blustein
Date: Wed, 03 Apr 1996 13:10
16 lines
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
#2476
Author: Richard A. O'Keefe
Date: Wed, 03 Apr 1996 13:10
17 lines
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
#2489
Author: Konrad Schwarz
Date: Thu, 04 Apr 1996 00:56
23 lines
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
#2513
Author: telnet user
Date: Fri, 05 Apr 1996 00:38
58 lines
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
#2507
Author: Claude Quezel
Date: Fri, 05 Apr 1996 00:39
41 lines
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
#2573
Author: Henning Makholm
Date: Thu, 11 Apr 1996 18:54
15 lines
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
#2575
Author: ct
Date: Thu, 11 Apr 1996 23:51
23 lines
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