peterwu@microsoft.UUCP (Peter Wu ) (09/16/89)
What's the simplest way to obtain the sizeof a field inside a struc
without declaring a variable?
E.g:
struct abc {
int def;
char ghi;
long jkl;
};
I know this works:
#define SIZEGHI sizeof(((struct abc *)0)->ghi)
Is there a shorter way?
gwyn@smoke.BRL.MIL (Doug Gwyn) (09/17/89)
In article <7710@microsoft.UUCP> peterwu@microsoft.UUCP (Peter Wu ) writes: >What's the simplest way to obtain the sizeof a field inside a struc >without declaring a variable? >struct abc { > int def; > char ghi; > long jkl; >}; >I know this works: >#define SIZEGHI sizeof(((struct abc *)0)->ghi) No, that doesn't necessarily work. Review the interminable discussions about use of null pointers. #define SIZEGHI (sizeof(char)) works. There's no way to do this using the member name but not its type, without using some presumed object. However, since the object need not exist for sizeof, you could try #define SIZEGHI (sizeof ((struct abc *)malloc(sizeof(struct abc)))->ghi)
tanner@cdis-1.uucp (Dr. T. Andrews) (09/18/89)
In article <11086@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
) [ [ #define SIZEGHI sizeof(((struct abc *)0)->ghi) ]...
) doesn't necessarily work. ]
Since you're not de-referencing the null pointer, you're going to
have a very hard time convincing me that there's an excuse for the
above to fail.
The same argument applies to the obvious "OFFSET_OF" implementation.
) Review the interminable discussions about use of null pointers.
Most of the discussions about NULL pointers have warned of the evils
of dereferencing them.
It has been noted that a particular object need not actually exist
for sizeof() to work.
) #define SIZEGHI (sizeof ((struct abc *)malloc(sizeof(struct abc)))->ghi)
And, why not use "blunge()" instead of malloc? We're not going to
call malloc() in the sizeof() context. Ah, yes, and we can
#define blunge(XX) ((char *)0) /* malloc may return NULL */
and of course we're right back to where we were at the start...
--
...!bikini.cis.ufl.edu!ki4pv!cdis-1!tanner ...!bpa!cdin-1!cdis-1!tanner
or... {allegra attctc gatech!uflorida}!ki4pv!cdis-1!tanner
stuart@dtix.dt.navy.mil (Pearlman) (09/19/89)
In article <11086@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes: :In article <7710@microsoft.UUCP> peterwu@microsoft.UUCP (Peter Wu ) writes: :>What's the simplest way to obtain the sizeof a field inside a struc :>without declaring a variable? :>struct abc { :> int def; :> char ghi; :> long jkl; :>}; :>I know this works: :>#define SIZEGHI sizeof(((struct abc *)0)->ghi) : :No, that doesn't necessarily work. Review the interminable discussions :about use of null pointers. I don't see what is wrong with Peter's method. Sizeof gets evaluated at compile time. In some instances, the address of its argument may not yet have been fixed by the compiler when it is evaluated. What is important is the type of sizeof's argument, and that certainly seems well defined. Or am I totally confused? Stuart Pearlman <stuart@dtix.dt.navy.mil> Hadron, Inc. 9990 Lee Hway. Fairfax, VA 22030 (703) 359-6100
gwyn@smoke.BRL.MIL (Doug Gwyn) (09/20/89)
In article <131@dtoa3.dt.navy.mil> stuart@dtix.dt.navy.mil (Stuart Pearlman) writes: -In article <11086@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes: -:In article <7710@microsoft.UUCP> peterwu@microsoft.UUCP (Peter Wu ) writes: -:>#define SIZEGHI sizeof(((struct abc *)0)->ghi) -:No, that doesn't necessarily work. Review the interminable discussions -:about use of null pointers. -What is important is the type of sizeof's argument, and that certainly -seems well defined. Is the type of an illegal expression well defined? Perhaps it's the same as the type of one hand clapping.
jss@jra.ardent.com (Jerry Schwarz (Compiler)) (09/20/89)
In article <11110@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: With regard to a discussion of: sizeof(((struct abc *)0)->ghi) > >Is the type of an illegal expression well defined? >Perhaps it's the same as the type of one hand clapping. Which suggests that Doug believes that this is an illegal expression. But is it? It (the operand of sizeof) is an expression whose evaluation would result in undefined behavior, but does that make it illegal? I think not, and here it is used in a context where it explicitly will not be evaluated. I believe the above is a legal expression. Jerry Schwarz jss@ardent.com
gwyn@smoke.BRL.MIL (Doug Gwyn) (09/21/89)
In article <8361@ardent.UUCP> jss@jra.ardent.com (Jerry Schwarz (Compiler)) writes:
-With regard to a discussion of:
- sizeof(((struct abc *)0)->ghi)
-Which suggests that Doug believes that this is an illegal expression.
-But is it? It (the operand of sizeof) is an expression whose evaluation
-would result in undefined behavior, but does that make it illegal?
-I think not, and here it is used in a context where it explicitly will
-not be evaluated.
(((struct abc *)0)->ghi) is not a valid unary expression,
because the left-hand operand of the -> is not an lvalue
that points at an object (see 3.3.2.3 Semantics).
This has nothing to do with evaluation.
msb@sq.sq.com (Mark Brader) (09/25/89)
> > With regard to a discussion of: > > sizeof(((struct abc *)0)->ghi) > > ... > (((struct abc *)0)->ghi) is not a valid unary expression, > because the left-hand operand of the -> is not an lvalue > that points at an object (see 3.3.2.3 Semantics). The wording there -- I checked it, but don't have it at hand -- does indeed appear to make such a requirement. But if we interpret it in the way that Doug does, then we also have to forbid sizeof (foo->ghi) where foo is an otherwise unused, automatic variable of the appropriate pointer-to-struct type. Such a prohibition seems ridiculous to me. I claim that 3.3.2.3 must therefore describe the semantics of the -> operation only when such an operation is actually attempted. I think that the wording should have made clear that the result of "sizeof expression" is independent of the actual values entering into the expression, and that the (notional) type of the result of -> is the type of the member even when no result is possible. Similarly, sizeof(300*300) should be sizeof(int) whether or not the computation of 300*300 in ints causes an overflow trap, and so should sizeof(a*b) where a and b are otherwise unused auto ints. -- Mark Brader, SoftQuad Inc., Toronto, utzoo!sq!msb, msb@sq.com A standard is established on sure bases, not capriciously but with the surety of something intentional and of a logic controlled by analysis and experiment. ... A standard is necessary for order in human effort. -- Le Corbusier This article is in the public domain.
tanner@cdis-1.uucp (Dr. T. Andrews) (09/25/89)
In article <11120@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes: > (((struct abc *)0)->ghi) is not a valid unary expression, > because the left-hand operand of the -> is not an lvalue > that points at an object (see 3.3.2.3 Semantics). This is useful (mainly as an example of the distinction between "useful" and "very useful"). Consider... sizeof(p->member) /* size of specified member */ for struct blunge *p; a) If "p" hasn't yet been initialized, is it a valid expression? b) If "p" has been initialized to NULL, is it a valid expression? c) If "p" has been free()d, is it a valid expression? Of course, we might also ask about *p in another way: when is the expression p = (struct blunge *)malloc(sizeof(*p)) valid? Only AFTER it has been evaluated? If allowing case (b) above, kindly point out the distinction between it and #define p ((struct blunge *)0) If disallowing case (b), kindly justify this. Remember that we are not evaluating the argument to sizeof(). -- ...!bikini.cis.ufl.edu!ki4pv!cdis-1!tanner ...!bpa!cdin-1!cdis-1!tanner or... {allegra attctc gatech!uflorida}!ki4pv!cdis-1!tanner
gwyn@smoke.BRL.MIL (Doug Gwyn) (09/30/89)
In article <7646@cdis-1.uucp> tanner@cdis-1.uucp (Dr. T. Andrews) writes: >If disallowing case (b), kindly justify this. You're not allowed to feed garbage to sizeof(). ((type *)0)->anything is garbage. A strictly conforming program is not allowed to contain that construct. At least, that's my interpretation of the rules.
tanner@cdis-1.uucp (Dr. T. Andrews) (10/02/89)
In article <11185@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes: > You're not allowed to feed garbage to sizeof(). ((type *)0)->anything > is garbage. For some looping construct with "struct blunge *p;", then, we have the interesting cases: for ( p=0 ;; ) { /* p == (type *)0 */ /* ... */ if (some_cond1) sz = sizeof(p->member); /* garbage? */ if (some_cond2) p = p_malloc(sizeof(*p)); /* garbage? */ /* ... */ } Remember that sizeof() is a compile-time operation. Do we expect the compiler to do flow analysis to determine whether we are feeding a valid pointer into a sizeof() expression? I should be pleased to hear WHY (((type *)0)->anything) is disallowed in the context of compile-time expressions. Is there some existing compiler in which it is disallowed (why?) or has X3J11, after some careful consideration, noted that there is good reason to discourage it? Note that the bald assertion that it is "garbage" is a little hard to swallow. -- ...!bikini.cis.ufl.edu!ki4pv!cdis-1!tanner ...!bpa!cdin-1!cdis-1!tanner or... {allegra attctc gatech!uflorida}!ki4pv!cdis-1!tanner
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/06/89)
In article <7653@cdis-1.uucp>, tanner@cdis-1.uucp (Dr. T. Andrews) writes: | Remember that sizeof() is a compile-time operation. Do we expect | the compiler to do flow analysis to determine whether we are feeding | a valid pointer into a sizeof() expression? Why should flow analysis be needed? If the pointer is defined, call it p, then: sizeof(p) sizeof a pointer to a {type} sizeof(*p) sizeof an object of {type} -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/07/89)
In article <7653@cdis-1.uucp> tanner@cdis-1.uucp (Dr. T. Andrews) writes: >I should be pleased to hear WHY (((type *)0)->anything) is disallowed >in the context of compile-time expressions. Because (type *)0 is SYNTACTICALLY a null pointer, and there is a prohibition against using a null pointer as the left operand of ->.
tanner@cdis-1.uucp (Dr. T. Andrews) (10/09/89)
In article <11227@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
)) ... WHY (((type *)0)->anything) is disallowed in the context
)) of compile-time expressions.
) Because (type *)0 is SYNTACTICALLY a null pointer, and there is a
) prohibition against using a null pointer as the left operand of ->.
It is begging the question to say that "it is disallowed because it
is prohibited". The sizeof() operator is used to extract type
information, and the cited NULL pointer happens to come complete
with all of the required type information.
--
Cutting half of passenger service | {bpa,uunet}!cdin-1!cdis-1!tanner
Mulroney: "cold froze our brains" | {attctc gatech!uflorida}!ki4pv!cdis-1!tanner
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/12/89)
In article <7678@cdis-1.uucp> tanner@cdis-1.uucp (Dr. T. Andrews) writes: -In article <11227@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes: -)) ... WHY (((type *)0)->anything) is disallowed in the context -)) of compile-time expressions. -) Because (type *)0 is SYNTACTICALLY a null pointer, and there is a -) prohibition against using a null pointer as the left operand of ->. -It is begging the question to say that "it is disallowed because it -is prohibited". The sizeof() operator is used to extract type -information, and the cited NULL pointer happens to come complete -with all of the required type information. No, there IS no type information, because the construct is officially meaningless. You THINK you know what type was MEANT, but the compiler is not obliged to mimic your thought processes. This is not an issue about sizeof, but rather about ->.
dave@motto.UUCP (dave brown) (10/13/89)
In many articles many people write: all kinds of arguments about why or why not (((type *)0)->anything) is disallowed in the context of compile-time expressions. I apologize if I missed it, but is there a legal ANSI way of doing what the original poster wanted to do, which I assume was to assign the size of a structure to a variable at compile time. Thanks. ----------------------------------------------------------------------------- | David C. Brown | uunet!mnetor!motto!dave | | Motorola Canada, Ltd. | 416-499-1441 ext 3708 | | Communications Division | Disclaimer: Motorola is a very big company | -----------------------------------------------------------------------------
davies@uicsrd.csrd.uiuc.edu (10/13/89)
gwyn@smoke.BRL.MIL writes re: using sizeof((type *)0->field: ** **No, there IS no type information, because the construct is **officially meaningless. You THINK you know what type was MEANT, **but the compiler is not obliged to mimic your thought processes. ** **This is not an issue about sizeof, but rather about ->. If it is "officially meaningless" to use (type *)0->field, would it be "officially meaningful" to instead substitute (type *)1->field? After all, the pointer is no longer NULL, so it must be ok, right? This whole discussion seems a bit abstract - can anybody cite references from the standard or examples of compiler behaviour when confronted with something like this?
diamond@csl.sony.co.jp (Norman Diamond) (10/13/89)
>-)) ... WHY (((type *)0)->anything) is disallowed in the context >-)) of compile-time expressions. In article <11263@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >-) Because (type *)0 is SYNTACTICALLY a null pointer ... >... there IS no type information, because the construct is >officially meaningless. You THINK you know what type was MEANT, >but the compiler is not obliged to mimic your thought processes. >This is not an issue about sizeof, but rather about ->. No type information? int *ip; ip = (float *) 0; Is this legal? A null pointer can be assigned to ip. Null pointers have no type? -- Norman Diamond, Sony Corp. (diamond%ws.sony.junet@uunet.uu.net seems to work) The above opinions are inherited by your machine's init process (pid 1), after being disowned and orphaned. However, if you see this at Waterloo or Anterior, then their administrators must have approved of these opinions.
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/14/89)
In article <44200027@uicsrd.csrd.uiuc.edu>, davies@uicsrd.csrd.uiuc.edu writes: | This whole discussion seems a bit abstract - can anybody cite references | from the standard or examples of compiler behaviour when confronted | with something like this? Better yet, can someone post a method to get the size of a field without having to create the struct or union which *is* a. portable b. readable Why discuss the virtues of NULL and why it should be special in this case, assume that even if it works people will flame you for using it, and let someone prove how smart they are by posting a sloution to the problem. -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
jeenglis@nunki.usc.edu (Joe English) (10/14/89)
davidsen@crdos1.UUCP (bill davidsen) writes: > Better yet, can someone post a method to get the size of a field >without having to create the struct or union which *is* > a. portable > b. readable > > Why discuss the virtues of NULL and why it should be special in this >case, assume that even if it works people will flame you for using it, >and let someone prove how smart they are by posting a solution to the >problem. struct foo { ... sometype field; ... }; Use 'sizeof(sometype)' instead of 'sizeof(((struct foo *)0)->field)' See how smart I am? :-) Personally, I prefer 'sizeof(type)' over 'sizeof(object)' as a general rule anyway. This is not so good a solution when there is information hiding going on -- you know that struct foo has a field named 'field,' but its type may vary between versions of the program (different memory models under MS-DOS is one example, albeit a bad one), but that's where typedefs come in. --Joe English jeenglis@nunki.usc.edu
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/14/89)
In article <44200027@uicsrd.csrd.uiuc.edu> davies@uicsrd.csrd.uiuc.edu writes: >If it is "officially meaningless" to use (type *)0->field, >would it be "officially meaningful" to instead substitute >(type *)1->field? You mean ((type *)1)->field. This is explicitly implementation-dependent. Maybe it works and maybe it breaks horribly (as it would on most word-oriented machines).
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/14/89)
In article <10960@riks.csl.sony.co.jp> diamond@ws.sony.junet (Norman Diamond) writes: >Null pointers have no type? That's not what I've been saying. Garbage constructs have no type. ((thing*)0)->member is a garbage construct. It has no type. In case you don't know what I mean by "garbage construct", it is a sequence of C source characters for which the Standard assigns no valid meaning.
dave@dsi.COM (Dave Rifkind) (10/16/89)
In lots of articles (see References), lots of people say lots of things: Would you think me irascible if I were to say that youse guys have gone standard-happy? Doug Gwyn (I think) says that dereferencing a null pointer is "syntactically meaningless". Nuts! "Null pointer" is not a syntactic concept--it's meaningful only at runtime. Any pointer is potentially a null pointer; you can't determine "nullness" syntactically. To suggest that a compiler should police runtime errors at compile time is silly. It's the compiler's job to convert syntactically valid source into object code. It is not the compiler's job to worry about runtime semantics. And, yes, *every* pointer has a type. The contents of that pointer, whether constant at compile time or variable, do not affect this.
kremer@cs.odu.edu (Lloyd Kremer) (10/17/89)
In article <5752@merlin.usc.edu> jeenglis@nunki.usc.edu (Joe English) writes: >davidsen@crdos1.UUCP (bill davidsen) writes: >> Better yet, can someone post a method to get the size of a field >>without having to create the struct or union which *is* >> a. portable >> b. readable >> >> Why discuss the virtues of NULL and why it should be special in this >>case, assume that even if it works people will flame you for using it, >>and let someone prove how smart they are by posting a solution to the >>problem. > > >struct foo { > ... > sometype field; > ... >}; > >Use 'sizeof(sometype)' instead of 'sizeof(((struct foo *)0)->field)' Neither is adequate if you wish to know the effective size of the member including structure padding. On my 32-bit machine running System V UNIX I get: main() { struct foo { char field; }; printf("sizeof(char) == %d\n", sizeof(char)); printf("sizeof(field) == %d\n", sizeof(((struct foo *)0)->field)); printf("sizeof(struct foo) == %d\n", sizeof(struct foo)); return(0); } Output: sizeof(char) == 1 sizeof(field) == 1 sizeof(struct foo) == 4 -- Lloyd Kremer ...!uunet!xanth!kremer Have terminal...will hack!
ckl@uwbln.UUCP (Christoph Kuenkel) (10/17/89)
In article <11280@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes: > That's not what I've been saying. Garbage constructs have no type. > ((thing*)0)->member is a garbage construct. It has no type. > > In case you don't know what I mean by "garbage construct", it is > a sequence of C source characters for which the Standard assigns > no valid meaning. like ``<>??|.'' ? hm, perhaps you can cite a paragraph in the standard that says, subtracting 5 from a long int has no meaning assigned. should i scan the pANS for something like that? this discussion gets somewhat boring as long as the one side argues that ``the standard says so''. it should better be explained why it says so and what it says, how to solve the problem in question (yes, there was a real problem!). for me, ((thing *)0) sounds quite reasonable. i agree that there is no meaningfull evaluation. i never saw a compiler that claimed this construct to be ``syntactically wrong''. i think that it should be possible to ``assign'' meaning to that construct in an unambigous way. so *why* does the standard define it to be garbage? -- # include <std/disclaimer.h> Christoph Kuenkel/UniWare GmbH Kantstr. 152, 1000 Berlin 12, West Germany ck@tub.BITNET ckl@uwbln {unido,tmpmbx,tub}!uwbln!ckl
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/17/89)
In article <277@dsi.COM> dave@dsi.UUCP (Dave Rifkind) writes: >Doug Gwyn (I think) says that dereferencing a null pointer is >"syntactically meaningless". Nuts! "Null pointer" is not a syntactic >concept--it's meaningful only at runtime. Any pointer is potentially a >null pointer; you can't determine "nullness" syntactically. To suggest >that a compiler should police runtime errors at compile time is silly. I said that dereferencing a null pointer CONSTANT was meaningless, and it is EXACTLY the kind of thing I want compilers to check for me at compile time. There is no service being rendered by a compiler, when it is in a position to detect a usage error at compile time, silently proceeding to generate code that may blow up at run time.
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/17/89)
In article <10201@xanth.cs.odu.edu> kremer@cs.odu.edu (Lloyd Kremer) writes: >Neither is adequate if you wish to know the effective size of the member >including structure padding. Then use the difference of two offsetof()s. The size of struct padding is not very useful to know; it's the offset of a struct member that is the information of use in programming. offsetof() is required to be provided by the implementation precisely because there is no portable way of computing struct member offsets without it.
kremer@cs.odu.edu (Lloyd Kremer) (10/17/89)
In article <1890@uwbull.uwbln.UUCP> ckl@uwbln.UUCP (Christoph Kuenkel) writes: >for me, ((thing *)0) sounds quite reasonable. i agree that there is no >meaningfull evaluation. i never saw a compiler that claimed this >construct to be ``syntactically wrong''. i think that it should be >possible to ``assign'' meaning to that construct in an unambigous way. There is nothing wrong with ((thing *)0). It is a nil pointer to thing. The point is that you can't use it for anything other than to represent an invalid or currently unassigned pointer of that type. Specifically, you can't "bounce off" it using the -> operator and expect the compiler to know what you're talking about. P.S. I will concede that many compilers handle the construct the way you expect, but it is not legal ANSI C and is not portable. -- Lloyd Kremer ...!uunet!xanth!kremer Have terminal...will hack!
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/19/89)
In article <11316@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes: | I said that dereferencing a null pointer CONSTANT was meaningless, | and it is EXACTLY the kind of thing I want compilers to check for | me at compile time. But the pointer is not being dereferenced. A pointer can't be dereferenced at compile time. Examples which work with pcc and gcc and appear valid as I read the standard: (1) int *foo = (int *)0; int bar = sizeof(*foo); (2) void test(x) struct mytype *x; { int m = sizeof(x->a); /* x certainly could be NULL */ } Now the pointer foo is not being dereferenced, sizeof a pointer with an indirect is evaluated by taking the size of the type of the object to which the pointer *may* validly point. This is done at compile time, asis example (2), where the type of field a within struct mytype is used to set the initializer. What the original poster wanted was the size of a field within a struct. He proposed using: sizeof(((struct mytype *)0)->field) which involves using a null values pointer. The value of this under pcc compilers is the size of the field within a struct mytype. You interpret the standard to forbid this. Do you also interpret the standard to forbid: struct mytype { int a, b; } *head = (struct mytype)0; int fieldlen = sizeof(head->a); I would first note that sizeof always works on the *type* of the object. Not only things like "sizeof(int)" but "sizeof(xyz)" must be done by type, since xyz is not an allocated object at compile time, what is really delivered by the sizeof operator is the size of the generic type of xyz. I realize that there are good reasons for not dereferencing NULL pointers, but since the sizeof operator actually returns the size of the *type* of the specified object, I certainly can't see any technical reason why the original construct should be rejected, since the type information is available at compile time, and the value of the pointer is not. The compiler can't validate the value of the pointer in any other case, why should it be required or even allowed to do so in this case. Here's what the standard says (3.3.3.4): The *sizeof* operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an lvalue that designates a bitfield object. The *sizeof* operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined by the type of the operand, which is not itself evaluated. The result is an integer constant. ================ end quote ================ If the expression is not evaluated the pointer is not dereferenced and there is no problem as far as hypothetical hardware which checks for this. I see nothing which I can read to forbid the original construct or indicate that it might not be valid in this case. The meaning of an incomplete type is spelled out in 3.1.2.5 and a null pointer with a cast isn't shown. I therefore conclude that the construct of the original poster is valid C as specified by the standard. I also really wonder why sizeof doesn't return "unsigned int" but I suspect i wouldn't like the answer. -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
diamond@csl.sony.co.jp (Norman Diamond) (10/19/89)
In article <277@dsi.COM> dave@dsi.UUCP (Dave Rifkind) writes: >>"Null pointer" is not a syntactic >>concept--it's meaningful only at runtime. In article <11316@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >I said that dereferencing a null pointer CONSTANT was meaningless, >and it is EXACTLY the kind of thing I want compilers to check for >me at compile time. There is no service being rendered by a compiler, >when it is in a position to detect a usage error at compile time, >silently proceeding to generate code that may blow up at run time. (Dereferencing a null pointer NON-CONSTANT is just as meaningless.) Sure, I'd be glad to have the compiler help diagnose errors at compile time, under any condition where it knows appropriate information. This entire argument concerns a null pointer constant inside a _sizeof_ expression. Mr. Gwyn, if your compiler is in a position to detect a usage error at compile time, but it silently proceeds to generate code TO EVALUATE SIZEOF that may blow up at run time, or if it even generates code TO EVALUATE SIZEOF which will not blow up at run time, I'd say you have a pretty bad compiler. The entire reason this argument exists is that _sizeof_ does not generate any code, it does not dereference a null pointer, and it doesn't even stick a null segment pointer into a segment register. Until this posting of Mr. Gwyn's, I thought both sides had valid points. -- Norman Diamond, Sony Corp. (diamond%ws.sony.junet@uunet.uu.net seems to work) Should the preceding opinions be caught or | James Bond asked his killed, the sender will disavow all knowledge | ATT rep for a source of their activities or whereabouts. | licence to "kill".
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/19/89)
In article <1890@uwbull.uwbln.UUCP> ckl@uwbln.UUCP (Christoph Kuenkel) writes: >In article <11280@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes: >> That's not what I've been saying. Garbage constructs have no type. >> ((thing*)0)->member is a garbage construct. It has no type. >for me, ((thing *)0) sounds quite reasonable. ... >so *why* does the standard define it to be garbage? Why is it that people keep citing one thing then reading it as something else? ((thing *)0) is of course JUST FINE. How about reading what I SAID.
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/19/89)
In article <1234@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes: >What the original poster wanted was the size of a field within a struct. >He proposed using: > sizeof(((struct mytype *)0)->field) >which involves using a null values pointer. The value of this under pcc >compilers is the size of the field within a struct mytype. You interpret >the standard to forbid this. No, what I say is that the Standard does not require that it work as the programmer seems to expect it to. That's not the same thing. A conforming implementation is free to make it work if it so chooses. It is also free to not make it work. >Do you also interpret the standard to forbid: > int fieldlen = sizeof(head->a); Of course not. It does forbid int fieldlen = sizeof(((struct mytype*)0)->a). As I keep telling you, it is NOT an issue about sizeof! It's an issue about ->. So long as you persist in trying to determine this by reading the sizeof specs in the Standard, you'll never understand what I'm saying.
datanguay@watmath.waterloo.edu (David Adrien Tanguay) (10/19/89)
In article <1234@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
]
]Here's what the standard says (3.3.3.4):
] [quotes the standard]
]
]If the expression is not evaluated the pointer is not dereferenced and
]there is no problem as far as hypothetical hardware which checks for
]this. I see nothing which I can read to forbid the original construct
]or indicate that it might not be valid in this case. The meaning of an
]incomplete type is spelled out in 3.1.2.5 and a null pointer with a
]cast isn't shown. I therefore conclude that the construct of the
]original poster is valid C as specified by the standard.
See also section 3.3.2.3, on the '->' and '.' operators. It eventually
says "...designates a member of a structure or union object." and
"... is an lvalue.". ((struct foo *)0)->elem does not designate an
object. Is there a clearer indication elsewhere?
]I also really
]wonder why sizeof doesn't return "unsigned int" but I suspect i wouldn't
]like the answer.
Unsigned int might not be large enough to hold the size of an object.
E.g., an IBM PC with huge objects.
David Tanguay
jeffa@hpmwtd.HP.COM (Jeff Aguilera) (10/20/89)
Doug Gwyn is determined to make C useless. If sizeof((T*)0->member) is not valid in ANSI C, then ANSI C must be changed. C is too valuable a programming language to prohibit useful constructs just because a few zealous pedants dislike them.
tanner@cdis-1.uucp (Dr. T. Andrews) (10/20/89)
) I said that dereferencing a null pointer CONSTANT was meaningless, ) and it is EXACTLY the kind of thing I want compilers to check for ) me at compile time. There is no service being rendered by a compiler, ) when it is in a position to detect a usage error at compile time, ) silently proceeding to generate code that may blow up at run time. I would suggest that, since sizeof() generates an integral constant, that any compiler which generated code which blew up for sizeof(((type *)0)->member) /* cited construct */ has a basic flaw. So far, we have heard that dereferencing a null pointer is garbage (but we aren't dereferencing one), and that null pointer CONSTANTS shouldn't be dereferenced (we still aren't dereferencing one), and that an explicitly cast null pointer lacks type information (a claim which is hard to swallow). What we have not heard is a convincing explanation of why the cited construct should be considered harmful. No excuse for an implementation that might blow up on it has been given. Further, no useful alternative has (to date) shown up. -- Cutting half of passenger service | {bpa,uunet}!cdin-1!cdis-1!tanner Mulroney: "cold froze our brains" | {attctc gatech!uflorida}!ki4pv!cdis-1!tanner
bill@twwells.com (T. William Wells) (10/21/89)
In article <1234@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
: Here's what the standard says (3.3.3.4):
:
: The result is an integer constant.
: I also really
: wonder why sizeof doesn't return "unsigned int" but I suspect i wouldn't
: like the answer.
Watch that wording!
The quoted material says that sizeof results in an integer
constant, not that it results in a constant of type int.
Sizeof returns something of type size_t, which must be unsigned.
Unsigned of *some* type. It might be unsigned short :-) but I
suspect that the intent was to permit unsigned long.
---
Bill { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com
ok@cs.mu.oz.au (Richard O'Keefe) (10/21/89)
In article <7685@cdis-1.uucp>, tanner@cdis-1.uucp (Dr. T. Andrews) writes: > What we have not heard is a convincing explanation of why the cited > construct should be considered harmful. No excuse for an > implementation that might blow up on it has been given. Further, > no useful alternative has (to date) shown up. I'm sure I'll be corrected if I'm wrong, but isn't the actual restriction that the argument of "sizeof" must be an L-value in ANSI C? If I'm right about that, then the problem is not that sizeof ((struct foo*)NULL)->field may "blow up", but that ((struct foo*)NULL)->field is not an L-value.
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/22/89)
In article <7685@cdis-1.uucp> tanner@cdis-1.uucp (Dr. T. Andrews) writes: [I (Gwyn) said previously:] >) I said that dereferencing a null pointer CONSTANT was meaningless, Please IGNORE the rest of that, because it is a side issue having NOTHING to do with the formal logical argument against > sizeof(((type *)0)->member) /* cited construct */ I was responding there to your claim that the compiler shouldn't flag such misusage at compiler time, as a general principle, only loosely associated with this particular example. >So far, we have heard that dereferencing a null pointer is garbage >(but we aren't dereferencing one), and that null pointer CONSTANTS >shouldn't be dereferenced (we still aren't dereferencing one), If you take my discussion in its original context, it is clear that I'm using "dereference" as colloquial shorthand for "apply the -> operator to". >and that an explicitly cast null pointer lacks type information (a claim >which is hard to swallow). You invented this last claim yourself, because I certainly never said it. I did say that the construct under discussion as the operand of sizeof has no valid type. In fact it has no validity, period. >What we have not heard is a convincing explanation of why the cited >construct should be considered harmful. No excuse for an >implementation that might blow up on it has been given. Further, >no useful alternative has (to date) shown up. I'm not obliged to address these points, although they were in fact given careful consideration by X3J11 while the Standard was being drafted. My argument is that the Standard deliberately does not assign a meaning for ((type *)0)->member This is a consequence of the semantics: "A postfix expression followed by an arrow -> and an identifier designates a member of a structure or union object". But there is no object in this case (a null pointer does not point to an object). Thus, even though the type constraints of the left operand were obeyed, this usage is a semantic violation. Being a meaningless construct, its type is of course also meaningless -- even though you think you know what it "should" be. And, finally, sizeof(meaningless) is still meaningless. If you want to argue that the Standard should have assigned a meaning in this case, you should have sent in a comment to that effect during the public review process. However, I doubt very much that you could have made a sufficiently persuasive case for it.
ag@cbmvax.UUCP (Keith Gabryelski) (10/23/89)
I didn't see this come up anywhere...
> sizeof(((type *)0)->member) /* cited construct */
Is there a problem with declaring the structure pointer as an extern
and then doing the sizeof thang? As:
extern struct foo *Foo;
sizeof Foo->member
This requires no data allocation which was the original gripe, eh?
Pax, Keith
Ps, This casting NULL to some structure pointer then grabbing a member
from it FOR ANY REASON seems dubious, at best, to me. $.02.
--
"It took no computation to dance to the rock 'n roll station" -- VU
ag@cbmvax.commodore.com Keith M. Gabryelski ...!uunet!cbmvax!ag
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/23/89)
In article <30488@watmath.waterloo.edu>, datanguay@watmath.waterloo.edu (David Adrien Tanguay) writes: | davidsen@crdos1.UUCP (bill davidsen) writes: | ] | ]Here's what the standard says (3.3.3.4): | ] [quotes the standard] | ] | ]If the expression is not evaluated the pointer is not dereferenced and | ]there is no problem as far as hypothetical hardware which checks for | ]this. I see nothing which I can read to forbid the original construct | ]or indicate that it might not be valid in this case. The meaning of an | ]incomplete type is spelled out in 3.1.2.5 and a null pointer with a | ]cast isn't shown. I therefore conclude that the construct of the | ]original poster is valid C as specified by the standard. | | See also section 3.3.2.3, on the '->' and '.' operators. It eventually | says "...designates a member of a structure or union object." and | "... is an lvalue.". ((struct foo *)0)->elem does not designate an | object. Is there a clearer indication elsewhere? Footnote 45 states that any operator in 3.3 (which includes the ->) may be used, and that the expression is not evaluated except as to type. That means the NULL pointer expression is not evaluated. Ever. If the expression is not legal then compiler must make a spacial case, since (assuming that X is a pointer to struct containing field) sizeof(X->field) is certainly valid. | Later I said: | ]I also really | ]wonder why sizeof doesn't return "unsigned int" but I suspect i wouldn't | ]like the answer. | | Unsigned int might not be large enough to hold the size of an object. | E.g., an IBM PC with huge objects. This may be a bit of confusion in the standard, it says two things about the type, in 3.3.3.4 (pg 44 line 29) it says "the result is an integer constant" while on the next page it say the result is size_t and is unsigned. I was looking at the first explanation and wondering if the standard was leaving room for negative sizes ;-) The meaning is clear, I just read part of the section and didn't see the rest. I would like to see the first part say "unsigned" to match the rest of the section. -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/25/89)
In article <2488@munnari.oz.au>, ok@cs.mu.oz.au (Richard O'Keefe) writes: | I'm sure I'll be corrected if I'm wrong, but isn't the actual restriction | that the argument of "sizeof" must be an L-value in ANSI C? If I'm right | about that, then the problem is not that sizeof ((struct foo*)NULL)->field | may "blow up", but that ((struct foo*)NULL)->field is not an L-value. The standard says that you may take the sizeof an array, so the expression most definitely does not have to be an lvalue. You can also take sizeof something const. -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
chris@mimsy.umd.edu (Chris Torek) (10/25/89)
>In article <2488@munnari.oz.au> ok@cs.mu.oz.au (Richard O'Keefe) writes: >>... isn't the actual restriction that the argument of "sizeof" must be >>an L-value in ANSI C? ... ((struct foo*)NULL)->field is not an L-value. In article <1423@crdos1.crd.ge.COM> davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) writes: >The standard says that you may take the sizeof an array, so the >expression most definitely does not have to be an lvalue. You can also >take sizeof something const. According to the standard, arrays and consts are `non modifiable lvalue's (which rather contradicts the original meaning of l-value!). Anyway, I happen to think that `sizeof(*(type *)junk)' and similar constructs ought to be acceptable for any parse-able, cast-able `junk'. The standard happens to disagree. This is Just One Of Those Things. -- `They were supposed to be green.' In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/25/89)
In article <1323@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes: >... the expression is not evaluated except as to type. Designation is not the same as evaluation. That's why this is a compile-time error.
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/25/89)
In article <680011@hpmwjaa.HP.COM> jeffa@hpmwtd.HP.COM (Jeff Aguilera) writes: >Doug Gwyn is determined to make C useless. If sizeof((T*)0->member) >is not valid in ANSI C, then ANSI C must be changed. C is too >valuable a programming language to prohibit useful constructs just >because a few zealous pedants dislike them. Would you like to explain why, then, I have only ever needed to do something like that ONCE in my entire C programming career, and then it was merely in order to conform to somebody else's already- existing design botch? (Also, I later figured out a better solution.) Hardly "making C useless".
poser@csli.Stanford.EDU (Bill Poser) (10/25/89)
I am curious as to when someone would want to take sizeof(((T *) 0)->member).
If you need to know the size of a structure member, you can always consult
the structure definition, discover that member is, say, of type "int",
and write sizeof(int). If you want to allow for future changes in the
member's type, use the preprocessor and make both the definition and
the argument to sizeof macros, e.g.
#define INTEGRAL int
#define REAL double
struct foo{
INTEGRAL a;
REAL b;
};
Then you get the size of the a member as:
sizeof(INTEGRAL)
Perhaps one can argue that this isn't the most perspicuous thing to do,
but it seems easy enough that I am curious as to how outlawing the
null pointer construction can be seen as reducing C functionality in
any significant way.
Bill
kenny@m.cs.uiuc.edu (10/26/89)
Hey, wait a minute here. Is it just the constant NULL that can't be `dereferenced' in a sizeof expression, or is it any possibly invalid pointer? The discussion seems to indicate that the common idiomatic macro definition #define NEW(p) ((p) = malloc_and_check ((size_t) (sizeof *(p)))) (assuming that malloc-and-check never returns NULL, but throws a signal, longjmps, or something), is illegal under the proposed standard, because it dereferences the uninitialized pointer p. I find it hard to believe that this behavior was the intent of the Committee. If this interpretation is correct, I can still live with it by making a NEW macro for every type (typeof wasn't accepted, so I can't determine the size of the object without knowing the name of the type, unless I can write sizeof *p), or by passing the type name as a macro parameter, but it's pretty bogus. I hope at least that the Standard doesn't require that I go out of my way to make this NOT work. I can't imagine any way that a sane compiler writer could have this fail, since you never even need to load the pointer p -- all the discussion of possible faults upon loading a pointer into a register doesn't apply, since this expression never examines the value of the pointer at all. I would submit that `dereferencing' a pointer should mean reading from or writing into the location to which it points. Just putting a * or -> on it doesn't do this in C. Kevin | / o Kevin Kenny KB9DLU (217) 333-5821 |< /) | | | |/\ Department of Computer Science o , o , | \ X_ \/ | | | University of Illinois 40 07 N 88 13 W kenny@cs.uiuc.edu 1304 W. Springfield Ave. uunet!uiucdcs!kenny Urbana, IL 61801 AD ASTRA PER ARDUA k-kenny@uiuc.edu kenny%cs@uiucvmd.bitnet
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/26/89)
In article <680011@hpmwjaa.HP.COM>, jeffa@hpmwtd.HP.COM (Jeff Aguilera) writes: | Doug Gwyn is determined to make C useless. If sizeof((T*)0->member) | is not valid in ANSI C, then ANSI C must be changed. C is too | valuable a programming language to prohibit useful constructs just | because a few zealous pedants dislike them. ^^^^^^^^^^^^^^^ Whoa! If you can't find technical grounds to refute his arguments, don't stoop to personal attacks. I certainly disagree with Doug on this, not only on what it *should* mean, but what it *does* mean, but I won't get into a name calling contest. Doug has been helpful in clarifying a number of issues and should not be attacked personally because you disagree with him. Spend your time finding technical arguments, or send him personal hate mail. Just because he's totally wrong on this doesn't make him a bad person ;-) -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/26/89)
In article <10767@csli.Stanford.EDU>, poser@csli.Stanford.EDU (Bill Poser) writes: | I am curious as to when someone would want to take sizeof(((T *) 0)->member). | If you need to know the size of a structure member, you can always consult | the structure definition, discover that member is, say, of type "int", | and write sizeof(int). If you want to allow for future changes in the | member's type, use the preprocessor and make both the definition and | the argument to sizeof macros, e.g. This is just not practical unless you control the header file. There are times when a field in a structure may not be the same type (portably). While it's nice to dream of compliant C, you don't run real software on it. A field might be short on a VAX, int on a PC, and fubar_t on an ANSI compiler. Therefore, to write code which is maximally portable you must take the sizeof the field. No one argued that you can't get the sizeof a field without using a cast zero with -> to do it, just that it was a useful way to do it, that most current compilers support it, that no one has proposed a simple alternative which doesn't increase program size, and I have argued that that I still think it's legal under the standard. For all the people who proposed using an extern and not defining it, that generates a linker error on some systems and is not portable. A conforming implementation does not have to ignore extern declarations which are not used. -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
dhesi@sunseeker.UUCP (Rahul Dhesi) (10/26/89)
In article <11372@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >My argument is that the Standard deliberately does not >assign a meaning for > ((type *)0)->member >This is a consequence of the semantics: "A postfix expression followed >by an arrow -> and an identifier designates a member of a structure or >union object". But there is no object in this case (a null pointer >does not point to an object). I find this argument persuasive. However, the argument is persuasive only because the constant 0 has a special meaning in C. We know a null pointer does not point to an object. But what happens if we do the following? sizeof ((type *)1)->member There might or might not be an object in this case. It depends on the implementation. The C standard cannot guarantee that (type *)1 points to a valid object. It also cannot guarantee that it doesn't. A warning is probably in order, but it would be wrong for the C compiler to consider this an error *purely because of what the standard says*. If the compiler is smart enough to recognize that (type *)1 does not in fact point to a valid object, *then* it should complain. (But, unless you want to prevent people from writing device drivers, it had better still only give a warning, not a fatal compilation error.) It also occurs to me that sizeof ((type *)x)->member would be an interesting case to analyze, where x is some variable. At compile time x does not yet have a value, so we cannot guarantee that (type *)x points to any real object. What does the standard say about this? "gcc -ansi -pedantic" didn't seem to mind this: main() { int x; struct y { int a; int b; }; printf("size=%d\n", sizeof ((struct y *)x)->a); } I have lost track of how this controversy began, so I hope I haven't gone off at a tangent. Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com> UUCP: oliveb!cirrusl!dhesi Use above addresses--email sent here via Sun.com will probably bounce.
poser@csli.Stanford.EDU (Bill Poser) (10/26/89)
In article <1469@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes: > This [just doing sizeof(member) - BP] is just not practical unless > you control the header file. There are times when a field in a > structure may not be the same type (portably). I have two reactions to this. The first is that people who distribute libraries with headers that define structures with possibly variable (across implementation or time) members are doing a poor job if they don't either: (a) provide functions or macros which can be used to obtain the necessary information or (b) use macro definitions so that one can write,e.g. sizeof(INTEGRAL) instead of sizeof(int) or sizeof(short) or whatever. The second is that it is good to have the means to get around the deficiencies of suppliers who don't do this, so I will concede the utility of being able to do sizeof(struct->member). This makes me wonder whether it would not be worthwhile (in D, or whatever) to treat struct_type.member_name as a type alias, so that if we had: struct foo{ TYPE1 a; TYPE2 b; }; we could then use foo.a as a type, equivalent in this case to TYPE1. This would allow, in particular, the usage sizeof(foo.a).
mcdonald@uxe.cso.uiuc.edu (10/27/89)
>However, the argument is persuasive only because the constant 0 has a >special meaning in C. We know a null pointer does not point to an >object. But what happens if we do the following? > sizeof ((type *)1)->member How about /* suitable definition of type and member here */ void *a; size_t b = sizeof(((type *)a)->member); type *c; a = malloc(b); c = (type * )a; Somehow this begins to look awfully legal to me. What if the malloc was in another source file that was not linked in? Doug McDonald
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/27/89)
In article <1003@cirrusl.UUCP>, dhesi@sunseeker.UUCP (Rahul Dhesi) writes: | sizeof ((type *)x)->member If x is not a pointer type I'm sure you mean sizeof ((type *)&x)->member ^ This is the portable way to do it, but some compilers will complain mightily about casting the address of a non-struct to a struct. The most portable way would be to have a dummy variable of the pointer to struct type (or use one if you anready have it). -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/28/89)
In article <4700046@m.cs.uiuc.edu> kenny@m.cs.uiuc.edu writes: >#define NEW(p) ((p) = malloc_and_check ((size_t) (sizeof *(p)))) >[appears to be claimed to be] illegal under the proposed >standard, because it dereferences the uninitialized pointer p. No, there is nothing wrong with that; the argument of sizeof is not evaluated, and so a reference via the uninitialized pointer cannot occur. Since I'm the one claiming that sizeof(((foo*)0)->member) is invalid, let me try ONE MORE TIME to clarify what I think makes it invalid. It is invalid because the operand of sizeof is invalid, and the operand of sizeof is invalid because you are not allowed to write ((foo*)0)->member EVEN THOUGH the null pointer does have type "pointer to foo" (and we are assuming that foo objects do have "member" member designators). I believe that a compiler is allowed to diagnose that construct as an abuse of a null pointer constant. There may be Standard-wise people who disagree with me on this, but I haven't been getting much valid counterargument from them. There HAS been a lot of argument against points that I did not think I was trying to make!
kremer@cs.odu.edu (Lloyd Kremer) (10/28/89)
In article <1503@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes: >In article <1003@cirrusl.UUCP>, dhesi@sunseeker.UUCP (Rahul Dhesi) writes: > >| sizeof ((type *)x)->member > > If x is not a pointer type I'm sure you mean > sizeof ((type *)&x)->member > ^ I'm fairly sure he meant it the first way--an integral constant expression to be used as a pointer to some object (in this case a struct) in a totally non-portable way. Uses include accessing interrupt vectors or memory-mapped devices such as the video map or RAM designated for use by the system BIOS. One problem that comes to mind (other than obvious non-portability) is the familiar pointer alignment problem. I think ((type *)1)->member would cause a trap on any machine requiring any alignment of "type". Lloyd Kremer kremer@cs.odu.edu Have terminal...will hack!