[comp.std.c] [m]allocation question

ghoti+@andrew.cmu.edu (Adam Stoller) (09/19/90)

I've been looking at a book, "Algorithms in C" by Robert Sedgewick - and
although some of the coding examples are fairly sloppy (in terms of
error checking) I can understand that since that isn't the focus of the
book.  

However there is at least one piece of code where he allocates pointers
in a way I've never seen before -- and it isn't clear to me whether it
should work -- and was wondering if anyone could clarify it for me (in
regards to whether it works according to the Standard).

Example:

    static struct node
      { int key; struct node *next; };
    static struct node *head, *z, *t;
.....
    push (int v)
      {
        t = (struct node *) malloc(sizeof *t);
.....

Isn't *t garbage at the time the sizeof is performed - isn't this
[almost?] de-referencing a NULL pointer.

Traditionally, I believe, the above line is written:
        t = (struct node *) malloc (sizeof (struct node));
so my question is not how to correctly write the allocation, but whether
his method of writing it is at all acceptable?

Primarilly curious,

--fish

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/26/90)

In article <UaxqffS00Vtq8akksB@andrew.cmu.edu> ghoti+@andrew.cmu.edu (Adam Stoller) writes:
>         t = (struct node *) malloc(sizeof *t);

The argument of sizeof isn't evaluated. Only its type matters. This is
correct code, and perhaps easier to understand than the other obvious
version.

---Dan

henry@zoo.toronto.edu (Henry Spencer) (09/27/90)

In article <UaxqffS00Vtq8akksB@andrew.cmu.edu> ghoti+@andrew.cmu.edu (Adam Stoller) writes:
>        t = (struct node *) malloc(sizeof *t);
>.....
>Isn't *t garbage at the time the sizeof is performed - isn't this
>[almost?] de-referencing a NULL pointer.

No; the operand of a sizeof is never evaluated.  The compiler notes its
type but does not generate code for it.  Beware:  this was not entirely
clear in K&R1 and some old compilers may violate the rule.
-- 
TCP/IP: handling tomorrow's loads today| Henry Spencer at U of Toronto Zoology
OSI: handling yesterday's loads someday|  henry@zoo.toronto.edu   utzoo!henry

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/28/90)

In article <UaxqffS00Vtq8akksB@andrew.cmu.edu> ghoti+@andrew.cmu.edu (Adam Stoller) writes:
>        t = (struct node *) malloc(sizeof *t);
>Isn't *t garbage at the time the sizeof is performed - isn't this
>[almost?] de-referencing a NULL pointer.

We went through this about a year ago in a different guise.
The outcome of that discussion was that, since the argument to sizeof
is NOT evaluated, there is no attempt to access through that pointer,
and only the type (not the value) of the hypothetical result is
relevant.  Thus sizeof(*t) is obliged to work even if t contains a
garbage value.

jfh@rpp386.cactus.org (John F. Haugh II) (09/29/90)

In article <11666:Sep2603:44:3190@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>In article <UaxqffS00Vtq8akksB@andrew.cmu.edu> ghoti+@andrew.cmu.edu (Adam Stoller) writes:
>>         t = (struct node *) malloc(sizeof *t);
>
>The argument of sizeof isn't evaluated. Only its type matters. This is
>correct code, and perhaps easier to understand than the other obvious
>version.

I've been meaning to beg to differ, but looking at the code fragment,
the type of "t" is unknown, and thus the size of the allocation.  You
might argue that "t" is "obviously" (struct node *), but that would be
kinda silly - there is no declaration of "t" laying around to stare
at, and besides I'm just in the mood to argue.

I always try to "say what I mean" when I do mallocs and other naturally
obscure stuff (and I'm getting to the point, so bear with me) and would
prefer to do

	t = (struct node *) malloc (sizeof (struct node));

when it is a (struct node) that I want.  Otherwise, I would much
rather do

	t = (typeof t) malloc (sizeof *t);

but I don't recall "typeof" being part of the standard, so I'll have to
hope someone in alt.futures.c screams and dances about this one ;-)
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org
"SCCS, the source motel!  Programs check in and never check out!"
		-- Ken Thompson

cameron@usage.csd.oz (Cameron Simpson,Uhmmm..???? Who knows) (09/29/90)

From article <13946@smoke.BRL.MIL>, by gwyn@smoke.BRL.MIL (Doug Gwyn):
| In article <UaxqffS00Vtq8akksB@andrew.cmu.edu> ghoti+@andrew.cmu.edu (Adam Stoller) writes:
|>        t = (struct node *) malloc(sizeof *t);
|>Isn't *t garbage at the time the sizeof is performed - isn't this
|>[almost?] de-referencing a NULL pointer.
| 
| We went through this about a year ago in a different guise.
| The outcome of that discussion was that, since the argument to sizeof
| is NOT evaluated, there is no attempt to access through that pointer,
| and only the type (not the value) of the hypothetical result is
| relevant.  Thus sizeof(*t) is obliged to work even if t contains a
| garbage value.

This interests me. I seem to recall an extended discussion (maybe in
comp.std.c) concerning ways to determine the size of a structure member.
I have been using the macro

    /* size of a field - may break under ANSI, but hasn't yet */
    #define		fsizeof(type,field) sizeof(((type *)NULL)->field)

for some time. I have recollections of remarks to the effect that the
above locution could break under a conformant compiler. Could someone
either correct me ("yes, Cameron, fsizeof() is ok") or re-iterate the
explaination of why this macro can break, while sizeof(*t) is fine.
	- Cameron Simpson
	  cameron@spectrum.cs.unsw.oz.au

chris@mimsy.umd.edu (Chris Torek) (09/30/90)

In article <871@usage.csd.unsw.oz.au> cameron@usage.csd.oz
(Cameron Simpson,Uhmmm..???? Who knows) writes:
>I have been using the macro
>    #define		fsizeof(type,field) sizeof(((type *)NULL)->field)
>... Could someone ... re-iterate the explaination of why this macro
>can break, while sizeof(*t) is fine.

It is fairly simple:

	sizeof expression

and

	sizeof(type)

are both required to produce a compile-time constant, and to not evaluate
the expression at runtime (to boldly split an infinitive in the cause of
precision :-) ).  There is one constraint on *you*, however: all of the
`expression' or the `type' must be meaningful.

This gets a bit dodgy when it comes to expressions like

	((type *)NULL)->field

This consists of three sub-expressions, namely:

	NULL	(either 0 or (void *)0)
	cast	(to `type *')
	p->f	(select `field')

The NULL is certainly well-defined, as is the cast on it.  The question
comes down to `is nil->field well-defined?'.  The opinion seems to be that
it is not.  Most compilers are perfectly happy with it, but the ANSI
standard appears to allow them to be wroth.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

karl@haddock.ima.isc.com (Karl Heuer) (09/30/90)

In article <18552@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes:
>looking at the code fragment, the type of "t" is unknown... there is no
>declaration of "t" laying around...

Oh?  I think you overlooked this line from the original article:
|    static struct node *head, *z, *t;

>I always try to "say what I mean" [and hence write]
>	t = (struct node *) malloc (sizeof (struct node));

I happen to agree, but comp.std.c is not the place for style wars.  Both
`sizeof(*t)' and `sizeof(struct node)' are correct C, and we should leave it
at that.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

steve@taumet.com (Stephen Clamage) (09/30/90)

cameron@usage.csd.oz (Cameron Simpson,Uhmmm..???? Who knows) writes:

>I have been using the macro

>    /* size of a field - may break under ANSI, but hasn't yet */
>    #define		fsizeof(type,field) sizeof(((type *)NULL)->field)

>for some time. I have recollections of remarks to the effect that the
>above locution could break under a conformant compiler. Could someone
>either correct me ("yes, Cameron, fsizeof() is ok") or re-iterate the
>explaination of why this macro can break, while sizeof(*t) is fine.

As long as "type" in not an incomplete type and "field" is not a bit
field, this is perfectly fine.  The ANSI C standard explicitly
states that the expression argument of sizeof is not evaluated, so
NULL will not be derefrenced (which would be illegal).
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

karl@haddock.ima.isc.com (Karl Heuer) (09/30/90)

In article <26773@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>The opinion seems to be that [typed_nil_ptr->field] is not [well-defined].

My opinion differs, but the only one that counts is that of X3J11.
Didn't this get sent in for an official ruling?  If so, what was the answer?

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/30/90)

In article <871@usage.csd.unsw.oz.au> cameron@spectrum.cs.unsw.oz.au (Cameron Simpson) writes:
>From article <13946@smoke.BRL.MIL>, by gwyn@smoke.BRL.MIL (Doug Gwyn):
>| In article <UaxqffS00Vtq8akksB@andrew.cmu.edu> ghoti+@andrew.cmu.edu (Adam Stoller) writes:
>|>        t = (struct node *) malloc(sizeof *t);
>|>Isn't *t garbage at the time the sizeof is performed - isn't this
>|>[almost?] de-referencing a NULL pointer.
>| We went through this about a year ago in a different guise.
>| The outcome of that discussion was that, since the argument to sizeof
>| is NOT evaluated, there is no attempt to access through that pointer,
>| and only the type (not the value) of the hypothetical result is
>| relevant.  Thus sizeof(*t) is obliged to work even if t contains a
>| garbage value.
>This interests me. I seem to recall an extended discussion (maybe in
>comp.std.c) concerning ways to determine the size of a structure member.
>I have been using the macro
>    /* size of a field - may break under ANSI, but hasn't yet */
>    #define		fsizeof(type,field) sizeof(((type *)NULL)->field)
>for some time. I have recollections of remarks to the effect that the
>above locution could break under a conformant compiler. Could someone
>either correct me ("yes, Cameron, fsizeof() is ok") or re-iterate the
>explaination of why this macro can break, while sizeof(*t) is fine.

I probably overstated the validity of the construct "sizeof *t" when t
contains an invalid value.  Strictly speaking, 3.3.3.2 labels this a
case of "undefined behavior", and it doesn't state or imply that an
evaluation must be attempted for the result to be undefined.  However,
the normal implementation of sizeof() will not try to determine the
validity of the contents of t in such an expression, but will rather
rely solely on the type information, which is well-defined.  Thus, this
situation is one of those cases of "practically portable" rather than
"guaranteed portable" (among conforming implementations).  I personally
wouldn't use such a construction if it could be avoided.

The case of "sizeof ((type*)0)->field" is slightly more ambiguous --
the standard says in 3.3.2.3 Semantics that it "designates a member of
a structure or union object"; it also says what the value is, in terms
of thge pointed-to object, but that is not relevant in the context of
sizeof since there is no evaluation of the operand of sizeof.  A
reasonable argument can be given for either choice of interpretation;
I don't recall X3J11 having issued an interpretation ruling or a
response to public comment that specifically addresses this point.
It would be useful to obtain a definitive ruling on these examples.
Meanwhile, I recommend avoiding relying on such "grey areas" of the
language definition, because even if we all agree what the standard
says should happen, there is some chance that at least one actual
implementation will disagree, forcing you to change the code anyway.