[comp.lang.c] sizeof a struc field

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!