Base {}; sizeof(Base) == 1?

Discussion in 'C++' started by moleskyca1@yahoo.com, Aug 13, 2006.

  1. Guest

    This may be stupid question, but why is sizeof(Base) == 1 in:

    int main(int argc, char* argv[])
    {
    class Base
    {
    };
    cout << sizeof(Base) << endl;
    return 0;
    }

    I guess I want to know what the 1 byte is for? There is no vptr here,
    so why 1 byte?I checked FAQ and couldn't find answer.
    , Aug 13, 2006
    #1
    1. Advertising

  2. * :
    > This may be stupid question, but why is sizeof(Base) == 1 in:
    >
    > int main(int argc, char* argv[])
    > {
    > class Base
    > {
    > };
    > cout << sizeof(Base) << endl;
    > return 0;
    > }
    >
    > I guess I want to know what the 1 byte is for? There is no vptr here,
    > so why 1 byte?I checked FAQ and couldn't find answer.


    Needs a unique address.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Aug 13, 2006
    #2
    1. Advertising

  3. Daniel T. Guest

    In article <>,
    wrote:

    > This may be stupid question, but why is sizeof(Base) == 1 in:
    >
    > int main(int argc, char* argv[])
    > {
    > class Base
    > {
    > };
    > cout << sizeof(Base) << endl;
    > return 0;
    > }
    >
    > I guess I want to know what the 1 byte is for? There is no vptr here,
    > so why 1 byte?I checked FAQ and couldn't find answer.


    class Base { };

    int main() {
    Base bases[2];
    assert( &bases[0] != &bases[1] );
    }

    How could the compiler ensure the above assertion is true if sizeof(
    Base ) was 0?
    Daniel T., Aug 13, 2006
    #3
  4. Kai-Uwe Bux Guest

    Daniel T. wrote:

    > In article <>,
    > wrote:
    >
    >> This may be stupid question, but why is sizeof(Base) == 1 in:
    >>
    >> int main(int argc, char* argv[])
    >> {
    >> class Base
    >> {
    >> };
    >> cout << sizeof(Base) << endl;
    >> return 0;
    >> }
    >>
    >> I guess I want to know what the 1 byte is for? There is no vptr here,
    >> so why 1 byte?I checked FAQ and couldn't find answer.

    >
    > class Base { };
    >
    > int main() {
    > Base bases[2];
    > assert( &bases[0] != &bases[1] );
    > }
    >
    > How could the compiler ensure the above assertion is true if sizeof(
    > Base ) was 0?


    It could use infinitesimal pointer arithmetic: the size of an empty class
    could be infinitesimally small. A pointers and sizeinformation would
    contain an integer part and an infinitesimal part. Infinitesimal parts
    would be ignored for allocation of memory, but they would be taken into
    account for pointer arithmetic. The sizeof() operator would return the
    integer part of a size.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Aug 13, 2006
    #4
  5. moleskyca1 posted:

    > This may be stupid question, but why is sizeof(Base) == 1 in:
    >
    > int main(int argc, char* argv[])
    > {
    > class Base
    > {
    > };
    > cout << sizeof(Base) << endl;
    > return 0;
    > }
    >
    > I guess I want to know what the 1 byte is for? There is no vptr here,
    > so why 1 byte?I checked FAQ and couldn't find answer.



    To a large extent, C++ can be implemented in an "as if" way. Here's a
    sample program which prints the integers 0 through 9:

    #include <iostream>

    using std::cout;

    int main()
    {
    for(unsigned i = 0; i != 10; ++i)
    {
    cout << i << '\n';
    }
    }

    In accordance with the C++ Standard, this program must print the integers 0
    through 9... however it has much freedom in how it achieves this, just so
    long as the program works "as if" it were coded the original way. For all
    you know, the compiler may change it into:

    cout << 0U << '\n';
    cout << 1U << '\n';
    cout << 2U << '\n';
    cout << 3U << '\n';
    cout << 4U << '\n';
    cout << 5U << '\n';
    cout << 6U << '\n';
    cout << 7U << '\n';
    cout << 8U << '\n';
    cout << 9U << '\n';

    Or perhaps even:

    cout << "0\n1\n2\n3\n4\n5\n6\n7\n8\n9";

    This "as if" principle gives compilers great freedom.

    Every object (which is valid and has yet to be destroyed) must have a
    unique address. For example:

    struct MyStruct {};

    int main()
    {
    MyStruct obj1;
    MyStruct obj2;

    assert(&obj1 != &obj2);
    }

    If every object must have a unique address, then the byte (or perhaps the
    word) at that address cannot be used for anything else.

    In accordance with this, "sizeof" might return 1, or maybe even 4.

    However, in accordance with the "as if" principle, if you never take the
    address of an object in any form, then there's no reason why it must
    reserve memory. For instance, the compiler might change the following code:

    struct A {};
    struct B {};

    void Func(A) {}
    void Func(B) {}

    int main()
    {
    A a; B b;

    Func(a); Func(b);
    }

    into simply:

    void FuncA() {}
    void FuncB() {}

    int main()
    {
    FuncA(); FuncB();
    }

    Lastly, "sizeof" shall never yield zero.

    --

    Frederick Gotham
    Frederick Gotham, Aug 13, 2006
    #5
  6. Frederick Gotham posted:

    > If every object must have a unique address, then the byte (or perhaps
    > the word) at that address cannot be used for anything else.



    Actually, if you define the object as const, then perhaps the compiler may
    feel free to store its own personal data at that address (data which your
    program knows nothing about...)

    --

    Frederick Gotham
    Frederick Gotham, Aug 13, 2006
    #6
  7. Salt_Peter Guest

    wrote:
    > This may be stupid question, but why is sizeof(Base) == 1 in:
    >
    > int main(int argc, char* argv[])
    > {
    > class Base
    > {
    > };
    > cout << sizeof(Base) << endl;
    > return 0;
    > }


    corrected:
    ___
    # include <iostream>
    #include <ostream>

    class Base
    {
    };

    int main()
    {
    Base base;
    std::cout << sizeof( base ) << std::endl;
    }

    >
    > I guess I want to know what the 1 byte is for? There is no vptr here,
    > so why 1 byte?I checked FAQ and couldn't find answer.


    It isn't neccessarily 1 byte, that depends on the platform.

    Is base not an instance of type Base?
    Does it not therefore reside somewhere in memory in a concrete
    location?
    what you see is the "this" parameter.
    In otherwords, the programmer needs not track where base is because
    that instance already knows where it is located in memory.

    What if i defined Base like so...

    class Base
    {
    int m_n;
    public:
    Base(int n) : m_n( n ) { }
    ~Base() { }
    int get() const { return m_n; }
    };

    ....how would the program know which Base is which?

    int main()
    {
    Base base0( 10 );
    Base base1( 20 );

    std::cout << "base0 = " << base0.get() << std::endl;
    std::cout << "base1 = " << base1.get() << std::endl;
    }

    There is only one get() function placed in memory.
    However, get() receives the 'this' parameter - since get() is a member
    function.
    And that seemingly obscure this parameter is the key.
    The call to get() therefore receives the instances' address
    transparently.

    Of course, you can make get() to be a non-member:

    int get( Base* this) { return this->m_n; }

    int main()
    {
    Base base( 1 );
    std::cout << get( &base );
    }

    But all of a sudden, the encapsulated integer ( m_n) is no longer
    private.
    There is also a side-effect involved thats beyond the scope here.

    The cost of that 1 extra byte you saw before solves a whole littany of
    bugs and affords the programmer effective encapsulation + clear code.
    Salt_Peter, Aug 14, 2006
    #7
  8. Salt_Peter posted:

    > corrected:



    It was just a code snippet -- no need for pedantry.


    > What if i defined Base like so...
    >
    > class Base
    > {
    > int m_n;
    > public:
    > Base(int n) : m_n( n ) { }
    > ~Base() { }
    > int get() const { return m_n; }
    > };
    >
    > ...how would the program know which Base is which?



    This example has nothing to do with empty classes. Nonetheless, I would
    expect the following to evaluate to true:

    (void const*)&base == (void const*)&base.m_n


    > The cost of that 1 extra byte you saw before solves a whole littany of
    > bugs and affords the programmer effective encapsulation + clear code.



    No it doesn't. The question was about empty classes, i.e.:

    class MyClass {};

    You've used examples which have member data... so *of course* their size
    won't be zero.

    --

    Frederick Gotham
    Frederick Gotham, Aug 14, 2006
    #8
  9. Jerry Coffin Guest

    In article <ebnu57$9jm$>,
    says...

    [ ... ]

    > It could use infinitesimal pointer arithmetic: the size of an empty class
    > could be infinitesimally small. A pointers and sizeinformation would
    > contain an integer part and an infinitesimal part. Infinitesimal parts
    > would be ignored for allocation of memory, but they would be taken into
    > account for pointer arithmetic. The sizeof() operator would return the
    > integer part of a size.


    How exactly would you do that without storing the "infinitesimal" part
    as data in each object? If you did store it as data in the object, it
    appears that on a typical machine it would have to be _larger_ than one
    byte to distinguish more than 256 objects of that type. In fact, it
    would generally be on the same general size as an address, which is
    usually larger than a byte, by a factor of at least 2, often 4, and
    sometimes 8.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Aug 14, 2006
    #9
  10. Jerry Coffin Guest

    In article <xKRDg.12640$>,
    says...
    > Salt_Peter posted:


    [ ... ]

    > > class Base
    > > {
    > > int m_n;
    > > public:
    > > Base(int n) : m_n( n ) { }
    > > ~Base() { }
    > > int get() const { return m_n; }
    > > };


    [ ... ]

    > This example has nothing to do with empty classes. Nonetheless, I would
    > expect the following to evaluate to true:
    >
    > (void const*)&base == (void const*)&base.m_n


    With an aggregate, that's basically guaranteed. As-is, there's a good
    chance, but no certainty. At least with some implememtations, it would
    NOT be true if Base contained any virtual functions.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Aug 14, 2006
    #10
  11. Alex Vinokur Guest

    sizeof(EmptyStruct) in C and C++ (was: Base {}; sizeof(Base) == 1?)

    "Alf P. Steinbach" <> wrote in message news:...
    > * :
    > > This may be stupid question, but why is sizeof(Base) == 1 in:
    > >
    > > int main(int argc, char* argv[])
    > > {
    > > class Base
    > > {
    > > };
    > > cout << sizeof(Base) << endl;
    > > return 0;
    > > }
    > >
    > > I guess I want to know what the 1 byte is for? There is no vptr here,
    > > so why 1 byte?I checked FAQ and couldn't find answer.

    >
    > Needs a unique address.
    >


    struct Empty {};

    C: sizeof(Empty) == 0
    C++: sizeof(Empty) > 0

    Why doesn't C need a unique address?


    --
    Alex Vinokur
    email: alex DOT vinokur AT gmail DOT com
    http://mathforum.org/library/view/10978.html
    http://sourceforge.net/users/alexvn
    Alex Vinokur, Aug 14, 2006
    #11
  12. Re: sizeof(EmptyStruct) in C and C++ (was: Base {}; sizeof(Base) ==1?)

    "Alex Vinokur" <> writes:
    > "Alf P. Steinbach" <> wrote in message
    > news:...
    >> * :
    >> > This may be stupid question, but why is sizeof(Base) == 1 in:
    >> >
    >> > int main(int argc, char* argv[])
    >> > {
    >> > class Base
    >> > {
    >> > };
    >> > cout << sizeof(Base) << endl;
    >> > return 0;
    >> > }
    >> >
    >> > I guess I want to know what the 1 byte is for? There is no vptr here,
    >> > so why 1 byte?I checked FAQ and couldn't find answer.

    >>
    >> Needs a unique address.
    >>

    >
    > struct Empty {};
    >
    > C: sizeof(Empty) == 0
    > C++: sizeof(Empty) > 0
    >
    > Why doesn't C need a unique address?


    In C,
    struct Empty {};

    is a syntax error. (Some compilers might support that as an
    extension; if so, it's up to the compiler to decide what
    sizeof(struct Empty) should be.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Aug 14, 2006
    #12
  13. swets Guest

    Re: sizeof(EmptyStruct) in C and C++ (was: Base {}; sizeof(Base) == 1?)

    Keith Thompson wrote:
    > "Alex Vinokur" <> writes:
    > > "Alf P. Steinbach" <> wrote in message
    > > news:...
    > >> * :
    > >> > This may be stupid question, but why is sizeof(Base) == 1 in:
    > >> >
    > >> > int main(int argc, char* argv[])
    > >> > {
    > >> > class Base
    > >> > {
    > >> > };
    > >> > cout << sizeof(Base) << endl;
    > >> > return 0;
    > >> > }
    > >> >
    > >> > I guess I want to know what the 1 byte is for? There is no vptr here,
    > >> > so why 1 byte?I checked FAQ and couldn't find answer.
    > >>
    > >> Needs a unique address.
    > >>

    > >
    > > struct Empty {};
    > >
    > > C: sizeof(Empty) == 0
    > > C++: sizeof(Empty) > 0
    > >
    > > Why doesn't C need a unique address?

    >
    > In C,
    > struct Empty {};
    >
    > is a syntax error. (Some compilers might support that as an
    > extension; if so, it's up to the compiler to decide what
    > sizeof(struct Empty) should be.)
    >
    > --
    > Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    > San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    > We must do something. This is something. Therefore, we must do this.


    What is the size of a in
    int a[0];
    swets, Aug 14, 2006
    #13
  14. Guest

    Also, some compilers might/should optimize these empty classes if they
    are
    used as base classes for derived classes. In these cases, the
    compiler might/should skip allocating that 1 byte.

    Tolga Ceylan
    , Aug 14, 2006
    #14
  15. Re: sizeof(EmptyStruct) in C and C++

    swets wrote:

    > What is the size of a in
    > int a[0];


    A zero size array is illegal according to ANSI C.


    Igmar
    Igmar Palsenberg, Aug 14, 2006
    #15
  16. Kai-Uwe Bux Guest

    Jerry Coffin wrote:

    > In article <ebnu57$9jm$>,
    > says...
    >
    > [ ... ]
    >
    >> It could use infinitesimal pointer arithmetic: the size of an empty class
    >> could be infinitesimally small. A pointers and sizeinformation would
    >> contain an integer part and an infinitesimal part. Infinitesimal parts
    >> would be ignored for allocation of memory, but they would be taken into
    >> account for pointer arithmetic. The sizeof() operator would return the
    >> integer part of a size.

    >
    > How exactly would you do that without storing the "infinitesimal" part
    > as data in each object? If you did store it as data in the object, it
    > appears that on a typical machine it would have to be _larger_ than one
    > byte to distinguish more than 256 objects of that type. In fact, it
    > would generally be on the same general size as an address, which is
    > usually larger than a byte, by a factor of at least 2, often 4, and
    > sometimes 8.


    Infinitesimal parts would not need to be stored in the object, they would be
    part of the address, i.e., pointers would be longer. However, since
    infinitesimal parts can be ignored most of the time, it is very likely that
    the compiler could optimize away that overhead for almost all types within
    any given program.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Aug 14, 2006
    #16
  17. Jerry Coffin posted:

    >> This example has nothing to do with empty classes. Nonetheless, I would
    >> expect the following to evaluate to true:
    >>
    >> (void const*)&base == (void const*)&base.m_n

    >
    > With an aggregate, that's basically guaranteed. As-is, there's a good
    > chance, but no certainty. At least with some implememtations, it would
    > NOT be true if Base contained any virtual functions.



    If Base were a POD, then we'd have a guarantee. Since it's not, we don't.

    --

    Frederick Gotham
    Frederick Gotham, Aug 14, 2006
    #17
  18. Marcus Kwok Guest

    wrote:
    > This may be stupid question, but why is sizeof(Base) == 1 in:
    >
    > int main(int argc, char* argv[])
    > {
    > class Base
    > {
    > };
    > cout << sizeof(Base) << endl;
    > return 0;
    > }
    >
    > I guess I want to know what the 1 byte is for? There is no vptr here,
    > so why 1 byte?I checked FAQ and couldn't find answer.


    This is answered on Bjarne Stroustrup's FAQ:

    http://www.research.att.com/~bs/bs_faq2.html#sizeof-empty

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
    Marcus Kwok, Aug 14, 2006
    #18
  19. Jerry Coffin Guest

    In article <ebpb4m$qau$>,
    says...

    [ ... ]

    > Infinitesimal parts would not need to be stored in the object, they would be
    > part of the address, i.e., pointers would be longer.


    First of all, that doesn't strike me as changing much except the name
    you give to where you store it -- you're still creating a unique address
    for each object, just like you do right now. Under some circumstances
    you choose to ignore that difference, but it mostly seems to result in
    complexity with little or no benefit.

    It seems to me there's a much more straighforward method: nearly all
    modern systems support virtual memory anyway. Simply allocate a chunk of
    address space without any backing storage. Empty objects get allocated
    addresses without backing storage. Everything involved is then supported
    quite directly by typical hardware.

    > However, since
    > infinitesimal parts can be ignored most of the time, it is very likely that
    > the compiler could optimize away that overhead for almost all types within
    > any given program.


    Which (more likely than not) results in even further complexity or even
    more wasted space. For example, consider a situation where we cast from
    a pointer to derived to pointer to base, then back to pointer to derived
    (where the base is empty). In this case, we apparently need to add the
    "infinitesimal" part to the pointer during the cast to base, then strip
    it back off during the cast to derived -- or else we need to build in
    intelligence elsewhere to deal with the fact that a pointer to base may
    not always include an infinitesimal part, so everything that looks at a
    pointer to base needs to start by figuring out what kind of pointer it's
    dealing with.

    Except in rather limited situations, this doesn't gain us anything
    anyway -- we're changing the terminology from treating the stored data
    as part of the object to treating it as part of the pointer, but we're
    still stuck with the fact that we're storing some data for each object
    we create. Worse still, that's data that really needs to be stored,
    using up real memory, whereas simply assigning a new address to each
    object can be done without using any real memory to back those
    addresses. Worst of all, the amount of data we have to store will
    generally exceed the amount we'd use up even if we had backing storage
    for each object and assigned each its own address.

    The one place I can see this as a possible gain is if we have addresses
    with quite a few (at least 20 or so) address bits that are stored but
    not used. That, however, almost always means a processor that supports
    virtual memory anyway, so it would support the much simpler version I've
    outlined above.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Aug 14, 2006
    #19
  20. Jerry Coffin Guest

    In article <Fi1Eg.12649$>,
    says...

    [ given code like: ]

    (void const*)&base == (void const*)&base.m_n

    [ ... where m_n is the first element in base ... ]

    > If Base were a POD, then we'd have a guarantee. Since it's not, we don't.


    Actually, that's not quite true. Some of the things that most people
    think are guaranteed by being a POD (and were probably intended to be
    guaranteed) really aren't. For example:

    struct XX {
    int x;
    public:
    int y;
    };

    XX is a POD struct, but the presence of the access specifier (even
    though it's vacuous) allows the compiler to rearrange x and y as it sees
    fit.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Aug 15, 2006
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Derek
    Replies:
    7
    Views:
    24,324
    Ron Natalie
    Oct 14, 2004
  2. Trevor

    sizeof(str) or sizeof(str) - 1 ?

    Trevor, Apr 3, 2004, in forum: C Programming
    Replies:
    9
    Views:
    626
    CBFalconer
    Apr 10, 2004
  3. Vinu
    Replies:
    13
    Views:
    1,414
    Lawrence Kirby
    May 12, 2005
  4. Alex Vinokur
    Replies:
    7
    Views:
    496
    Clark S. Cox III
    Aug 14, 2006
  5. cppquester

    sizeof(derived) >= sizeof(base)?

    cppquester, Oct 7, 2011, in forum: C++
    Replies:
    1
    Views:
    304
    Juha Nieminen
    Oct 7, 2011
Loading...

Share This Page