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.