🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

6 total messages Started by Tom Payne Tue, 29 Aug 1995 04:14
Re: What is sizeof(T&) ??
#1860
Author: Tom Payne
Date: Tue, 29 Aug 1995 04:14
104 lines
5327 bytes
This posting follows up a posting in comp.lang.c++ dealing with the portion
of the draft standard that deals with sizeof applied to types.

In article <41nfb7$qau@druid.borland.com> Pete Becker (pete@borland.com) wrote:
 : 
 : In article <41lqnl$fgb@galaxy.ucr.edu>, thp@cs.ucr.edu says...
 : >
 : >As I read 5.3.3, it seems to support my claim:
 : >
 : >  1 The sizeof operator yields the number of bytes in the object represen-
 : >  tation of its operand.  The operand is either an expression, which  is
 : >  not  evaluated, or a parenthesized type-id.  The sizeof operator shall
 : >  not be applied to an expression that has function or incomplete  type,
 : >  or  to  an  enumeration  type  before  all  its  enumerators have been
 : >  declared, or to the parenthesized name of such types, or to an  lvalue
 : >  that   designates   a   bit-field.   [Note:  sizeof(char)  is  1,  but
 : >  sizeof(bool) and sizeof(wchar_t) are implementation-defined.  10)  See
 : >  _intro.memory_  for  the  definition of byte and _basic.types_ for the
 : >  definition of object representation.  ] 
 : >
 : >  2 When applied to a reference, the result is the size of the referenced
 : >  object.  ... 
 : >
 : >It seems to me that (2) above is somewhat redundant in that this is
 : >the way references work under all operations, as stated elsewhere.
 : >
 : >But, in the expression sizeof(Widget&), I am applying sizeof, not to a
 : >reference, but to a parenthesized type-id for a reference type, which
 : >should yield the number of bytes in the object representation of this
 : >operand, (Widget&).
 : >
 : >This is not an inference based on internal representation but my
 : >direct reading of a portion of the standard defines a language feature
 : >that reports a feature (size) of those representations to the
 : >programmer.
 : 
 : Widget& w = something;
 : 
 : Are you seriously arguing that sizeof(Widget&) need not be the same as 
 : sizeof(w)? Please apply a little common sense in reading the working paper. It 
 : is, after all, a document written by humans to be read by humans. It is not, 
 : and will not be, perfect. If it is possible to interpret something in a way 
 : that is clearly absurd, and it is also pssible to interpret the same thing in 
 : a way that is consistent with the rest of the paper and actually useful, do 
 : the latter.
 : 


Upon reading in a C++ book that it is often more efficient to pass
parameters by reference (because references are often smaller than
their referrentss), an experienced C programmer decides to determine
at what referrent size this effect becomes true.  Knowing, as all C
progrmmers do, that the sizeof operator "yields the number of bytes in
the object representation of its operand", which may be an expression
or the parenthesized name of a type, he immediately runs the program:

   #include <iostream.h>
   int main() { cout << sizeof(Widget&) << endl; }

The result, 17, he finds oddly coincidental; it's the same prime value
as sizeof(Widget).  

"How strange!"

He tries some other types with the even stranger result that in all
cases sizeof(T&) is equal to sizeof(T).

"Astonishing!!  So much for the book's claim that references are more
compact than their referrents.  But I wonder why these representations
vary in size this way."


Now, let's apply some common sense.  We can blame the victim,
insisting that he has failed to "apply a little common sense" and has
interpreted the C++ semantics of sizeof "in a way that is clearly
absurd."  Or, we can design the language in a way that minimizes the
astonishment factor by preserving the well-known semantics of sizeof.

There are two issues at hand:

  * What does the present wording say is the semantics of sizeof
    as it applies to parenthesized names of types?

  * What should be the semantics of sizeof as applied to 
    parenthesized names of types?

IMHO, logic, common sense, and good taste in language design all point
to a strict interpretation of the present wording.

Specifically, I find nothing in the present wording that would support
an interpretation that sizeof(T&) == sizeof(T).  Also, I find nothing
convincing about the argument that, because applying sizeof to a
reference expression, applying sizeof to a reference type must yield
the size of the referrent type.  It's similar to the non-sequitur that
brains can't think because neurons can't think.  There is no reason to
believe that properties of the components (in this case references)
can or must be shared by an ensemble (in this case a reference type).


Tom Payne (thp@cs.ucr.edu)
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: What is sizeof(T&) ??
#1864
Author: J. Kanze
Date: Tue, 29 Aug 1995 15:11
203 lines
9586 bytes
Tom Payne (thp@cs.ucr.edu) wrote:
|> This posting follows up a posting in comp.lang.c++ dealing with the portion
|> of the draft standard that deals with sizeof applied to types.

|> In article <41nfb7$qau@druid.borland.com> Pete Becker (pete@borland.com) wrote:
|>  : 
|>  : In article <41lqnl$fgb@galaxy.ucr.edu>, thp@cs.ucr.edu says...
|>  : >
|>  : >As I read 5.3.3, it seems to support my claim:
|>  : >
|>  : >  1 The sizeof operator yields the number of bytes in the object represen-
|>  : >  tation of its operand.  The operand is either an expression, which  is
|>  : >  not  evaluated, or a parenthesized type-id.  The sizeof operator shall
|>  : >  not be applied to an expression that has function or incomplete  type,
|>  : >  or  to  an  enumeration  type  before  all  its  enumerators have been
|>  : >  declared, or to the parenthesized name of such types, or to an  lvalue
|>  : >  that   designates   a   bit-field.   [Note:  sizeof(char)  is  1,  but
|>  : >  sizeof(bool) and sizeof(wchar_t) are implementation-defined.  10)  See
|>  : >  _intro.memory_  for  the  definition of byte and _basic.types_ for the
|>  : >  definition of object representation.  ] 
|>  : >
|>  : >  2 When applied to a reference, the result is the size of the referenced
|>  : >  object.  ... 
|>  : >
|>  : >It seems to me that (2) above is somewhat redundant in that this is
|>  : >the way references work under all operations, as stated elsewhere.
|>  : >
|>  : >But, in the expression sizeof(Widget&), I am applying sizeof, not to a
|>  : >reference, but to a parenthesized type-id for a reference type, which
|>  : >should yield the number of bytes in the object representation of this
|>  : >operand, (Widget&).
|>  : >
|>  : >This is not an inference based on internal representation but my
|>  : >direct reading of a portion of the standard defines a language feature
|>  : >that reports a feature (size) of those representations to the
|>  : >programmer.
|>  : 
|>  : Widget& w = something;
|>  : 
|>  : Are you seriously arguing that sizeof(Widget&) need not be the same as 
|>  : sizeof(w)? Please apply a little common sense in reading the working paper. It 
|>  : is, after all, a document written by humans to be read by humans. It is not, 
|>  : and will not be, perfect. If it is possible to interpret something in a way 
|>  : that is clearly absurd, and it is also pssible to interpret the same thing in 
|>  : a way that is consistent with the rest of the paper and actually useful, do 
|>  : the latter.
|>  : 


|> Upon reading in a C++ book that it is often more efficient to pass
|> parameters by reference (because references are often smaller than
|> their referrentss),

Most of the C++ books I've seen suggest passing parameters by reference
not because of the size, but because a reference does not require
calling the constructor.

|> an experienced C programmer decides to determine
|> at what referrent size this effect becomes true.  Knowing, as all C
|> progrmmers do, that the sizeof operator "yields the number of bytes in
|> the object representation of its operand", which may be an expression
|> or the parenthesized name of a type, he immediately runs the program:

|>    #include <iostream.h>
|>    int main() { cout << sizeof(Widget&) << endl; }

|> The result, 17, he finds oddly coincidental; it's the same prime value
|> as sizeof(Widget).  

|> "How strange!"

|> He tries some other types with the even stranger result that in all
|> cases sizeof(T&) is equal to sizeof(T).

|> "Astonishing!!  So much for the book's claim that references are more
|> compact than their referrents.  But I wonder why these representations
|> vary in size this way."


|> Now, let's apply some common sense.  We can blame the victim,
|> insisting that he has failed to "apply a little common sense" and has
|> interpreted the C++ semantics of sizeof "in a way that is clearly
|> absurd."  Or, we can design the language in a way that minimizes the
|> astonishment factor by preserving the well-known semantics of sizeof.

What are the well-known semantics of sizeof with regards to reference
types?

More importantly, what *do* you want the compiler to return for sizeof(
Widget& )?  What is the size of a reference?   Logically, I can see
several possibilities:

1. The size of Widget.  After all, a reference itself is just another
name for the object; why should sizeof( Widget& ) give different results
than sizeof( Widget )?

2. 0.  This is the minimum space needed to implement a reference.  In
many cases, it is all of the space the compiler will need.  In the other
cases, the additional space can be considered an implementation detail,
like padding, or the vptr.  On the other hand, this really doesn't seem
to be a very useful rule.

3. The actual space used.  This might work for expressions which result
in a reference type (except that no expression ever results in a
reference type), but since the actual space used varies from one use to
the next (on all of the compilers I'm familiar with), which one is the
compiler supposed to chose.

4. Make the construction illegal.  In one way, I'm tempted to argue that
this is implicitly the current status quo; sizeof( X ) gives the amount
of space an X occupies in an array, and since arrays of references are
illegal...

(Concerning the last, consider the following:

	struct X { int i ; char c ; } ;
	X				x ;
	char			c[ 3 ] ;

On my system, sizeof( X ) == 8, as does sizeof( x ).  And of course,
sizeof( c ) == 3.  Curiously, however, the two variables only take up a
total of 8 bytes; in this particular case, the physical sizeof x is 5,
and not 8.  This is a perfectly legal, and frequent, implementation.)

|> There are two issues at hand:

|>   * What does the present wording say is the semantics of sizeof
|>     as it applies to parenthesized names of types?

I think one could argue for 1 or 4, above, but I'm pretty sure that the
intent was 1.

|>   * What should be the semantics of sizeof as applied to 
|>     parenthesized names of types?

I'm beginning to think I prefer 4, but the issue of existing code speaks
in favor of 1.

|> IMHO, logic, common sense, and good taste in language design all point
|> to a strict interpretation of the present wording.

|> Specifically, I find nothing in the present wording that would support
|> an interpretation that sizeof(T&) == sizeof(T).  Also, I find nothing
|> convincing about the argument that, because applying sizeof to a
|> reference expression, applying sizeof to a reference type must yield
|> the size of the referrent type.  It's similar to the non-sequitur that
|> brains can't think because neurons can't think.  There is no reason to
|> believe that properties of the components (in this case references)
|> can or must be shared by an ensemble (in this case a reference type).

Just to cloud the issues:

Consider the following structure:

	struct X { Widget& w1 ; Widget& w2 ; X() ; } ;
	X				x ;

	//  We now have:
	sizeof( x ) < sizeof( x.w1 ) + sizeof( x.w2 )
	//  Or: the total is *less* than the sum of its parts.
	//  C programmers, of course, expect the inverse.

Another example:

	struct X { int& ri ; int i ; X() ;} ;
	X				x ;
	assert( (void*)( &x.ri ) == (void*)( &x ) ) ;

C programmers would normally expect the assertion to hold; after all,
``common sense'' (and the C standard) says that the address of the first
element of a structure is the same as the address of the structure.  (In
C++, this only holds for PODS's.)

Another interesting case:

	struct X { int i1 ; int& i2 ; int i3 ; X() ; } ;
	X				x ;

Again, the C standard requires that structure elements occur in order,
so the C programmer would expect that:

	(char*)( &x.i1 ) < (char*)( &x.i2 ) &&
	(char*)( &x.i2 ) < (char*)( &x.i3 )

Again, I don't think that this will ever be true.  Despite paragraph 11
section 9.2 of draft standard: ``Nonstatic data members of a class
declared without an intervening access specifier are allocated so that
later members have higher addresses within a class object.''  (The
reason: IMHO, i2 is not a ``nonstatic data member'', but simply a name
for an object.  The actual object is not necessarily even a member.)

About all I can conclude from this is that C++ is not C, and trying to
assimilate elements of C++ which are not found in C to elements which
are found in C is going to cause problems.
-- 
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle--
                             --Beratung in industrieller Datenverarbeitung

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: What is sizeof(T&) ??
#1880
Author: Tony Cook
Date: Fri, 01 Sep 1995 03:29
26 lines
1445 bytes
J. Kanze (kanze@gabi-soft.fr) wrote:
: (Concerning the last, consider the following:

: 	struct X { int i ; char c ; } ;
: 	X				x ;
: 	char			c[ 3 ] ;

: On my system, sizeof( X ) == 8, as does sizeof( x ).  And of course,
: sizeof( c ) == 3.  Curiously, however, the two variables only take up a
: total of 8 bytes; in this particular case, the physical sizeof x is 5,
: and not 8.  This is a perfectly legal, and frequent, implementation.)

Are you sure about this?  Considering X is a POD, what if the
programmer has coded:

	memset(&x, 0, sizeof(X));

somewhere in their program?  Or does this produce undefined
behaviour?
-- 
        Tony Cook - tony@online.tmx.com.au
                    100237.3425@compuserve.com

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: What is sizeof(T&) ??
#1881
Author: Steve Clamage
Date: Fri, 01 Sep 1995 04:00
34 lines
1668 bytes
tony@online.tmx.com.au (Tony Cook) writes:

>J. Kanze (kanze@gabi-soft.fr) wrote:

>: 	struct X { int i ; char c ; } ;
>: 	X				x ;
>: 	char			c[ 3 ] ;

>: On my system, sizeof( X ) == 8, as does sizeof( x ).  And of course,
>: sizeof( c ) == 3.  Curiously, however, the two variables only take up a
>: total of 8 bytes; in this particular case, the physical sizeof x is 5,
>: and not 8.  This is a perfectly legal, and frequent, implementation.)

>Are you sure about this?  Considering X is a POD, what if the
>programmer has coded:

>	memset(&x, 0, sizeof(X));

>somewhere in their program?  Or does this produce undefined
>behaviour?

I think James meant that only the first 5 bytes of the struct have
meaningful data; the rest is padding needed for alignment. The
compiler must allocate sizeof(X) bytes for any type X, if only
because distinct objects must not overlap.

--
Steve Clamage, stephen.clamage@eng.sun.com

---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: What is sizeof(T&) ??
#1889
Author: David Sachs
Date: Fri, 01 Sep 1995 17:24
30 lines
1962 bytes
>J. Kanze (kanze@gabi-soft.fr) wrote:
> (Concerning the last, consider the following:

> 	struct X { int i ; char c ; } ;
> 	X				x ;
> 	char			c[ 3 ] ;

> On my system, sizeof( X ) == 8, as does sizeof( x ).  And of course,
> sizeof( c ) == 3.  Curiously, however, the two variables only take up a
> total of 8 bytes; in this particular case, the physical sizeof x is 5,
> and not 8.  This is a perfectly legal, and frequent, implementation.)

This is perfectly legal, and will vary from system to system  

Presumably this was run on a system, where intergers require alignment
at a multiple of 4 bytes. In this case, struct X must be padded out to
a multiple of 4 bytes, in this case 8 bytes. The 3 unused bytes in an
object of type X, exist, but their contents are meaningless.

The padding ensures that the integer subobject i, will be properly
aligned if you define an array of X.
-- 
** The Klingons' favorite food was named by the first earthling to see it **
David Sachs - Fermilab, HPPC MS369 - P. O. Box 500 - Batavia, IL 60510
Voice: 1 708 840 3942      Deparment Fax: 1 708 840 3785


[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: What is sizeof(T&) ??
#1896
Author: J. Kanze
Date: Sun, 03 Sep 1995 16:01
48 lines
2655 bytes
Steve Clamage (clamage@Eng.Sun.COM) wrote:

|> tony@online.tmx.com.au (Tony Cook) writes:

|> >J. Kanze (kanze@gabi-soft.fr) wrote:

|> >: 	struct X { int i ; char c ; } ;
|> >: 	X				x ;
|> >: 	char			c[ 3 ] ;

|> >: On my system, sizeof( X ) == 8, as does sizeof( x ).  And of course,
|> >: sizeof( c ) == 3.  Curiously, however, the two variables only take up a
|> >: total of 8 bytes; in this particular case, the physical sizeof x is 5,
|> >: and not 8.  This is a perfectly legal, and frequent, implementation.)

|> >Are you sure about this?  Considering X is a POD, what if the
|> >programmer has coded:

|> >	memset(&x, 0, sizeof(X));

|> >somewhere in their program?  Or does this produce undefined
|> >behaviour?

|> I think James meant that only the first 5 bytes of the struct have
|> meaningful data; the rest is padding needed for alignment. The
|> compiler must allocate sizeof(X) bytes for any type X, if only
|> because distinct objects must not overlap.

Actually, I was just writing faster than I was thinking; what I said
(and meant) is wrong.  (I even think that there was a clarification with
regards to this in the C standard.)

What I think a compiler could do is apply the as-if rule.  A conforming
program cannot compare the address of x and the address of c; if the
compiler could determine that sizeof( X ) was never used to write
unsigned char's from the address of x (or something like that), then it
could allocate them without the padding.  Given the cost of memory, and
the complexity of the analysis necessary, I don't really expect to see
any compilers doing this, though.
-- 
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle--
                             --Beratung in industrieller Datenverarbeitung
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads