Compiler outputting wrong size

Main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Ex9_01.cpp
// Using a derived class
#include <iostream>                    // For stream I/O
#include "Box.h"
#include "CandyBox.h"                  // For CBox and CCandyBox
using std::cout;
using std::endl;


int main()
{
  CBox myBox(4.0, 3.0, 2.0);                     // Create CBox object
  CCandyBox myCandyBox;
  CCandyBox myMintBox("Wafer Thin Mints");       // Create CCandyBox object

  cout << endl
       << "myBox occupies " << sizeof myBox      // Show how much memory
       << " bytes" << endl                       // the objects require
       << "myCandyBox occupies " << sizeof myCandyBox
        << " bytes" << endl
       << "myMintBox occupies " << sizeof myMintBox
       << " bytes";

  cout << endl
       << "myBox length is " << myBox.m_Length;

  myBox.m_Length = 10.0;

  // myCandyBox.m_Length = 10.0;       // uncomment this for an error

  cout << endl;
  return 0;
}



Cbox:

1
2
3
4
5
6
7
8
9
10
11
12
// Header file Box.h in project Ex9_01
#pragma once

class CBox
{
  public:
    double m_Length;
    double m_Width;
    double m_Height;

    explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) : m_Length(lv), m_Width(wv), m_Height(hv){}
};



CCandyBox:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Header file CandyBox.h in project Ex9_01
#pragma once
#include <cstring>                                         // For strlen() and strcpy()
#include "Box.h"
class CCandyBox: CBox
{
  public:
    char* m_Contents;

    explicit CCandyBox(const char* str = "Candy")          // Constructor
    {
      m_Contents = new char[ strlen(str) + 1 ];
      strcpy_s(m_Contents, strlen(str) + 1, str);
    }

    ~CCandyBox()                                           // Destructor
    { delete[] m_Contents; };
};


Output:


myBox occupies 24 bytes
myCandyBox occupies 32 bytes
myMintBox occupies 32 bytes
myBox length is 4


Isnt the compiler outputting the wrong size for a CCandyBox? Shouldnt it be 28, it inherits 24 bytes from Cbox and 4 bytes for its pointer member. Where does the other 4 bytes come from?

Tried to do some research, I think its about the compiler aligning memory addresses or something.
Last edited on
Is this a simplified example? Those extra bytes would be coming from the vtable but I don't see any virtual functions here.
Nope its the one I compiled.
Nevermind - are you on a 64bit system? Pointers are not guaranteed to be 32 bits.
But my application is 32bit, which means its limited to only 2^32, but yea I am on a 64 bit system.
Microsoft's compiler allocates 8-bytes for each of the "doubles" of "CBox" which are aligned to an 8-byte boundary, and 4-bytes for the pointer data-member of "CCandyBox" which is aligned to a 4-byte boundary.

The additional 4-bytes are the padding bytes used to align the pointer data-member of "CBox" to the three "doubles" of "CCandyBox", giving you a total of 32-bytes. If, however, your application was 64-bit, the resulting size of "CCandyBox" would be the same.

Wazzak
Last edited on
What do you mean, "align".
By "align", I was referring to the placement or arrangement of data to some boundary. A "boundary" is an address divisible by some even number such as 8, 16, 32, 64, and so on.

Wazzak
But why is it doing that?
Ok LB thanks!

So it basically reads 8 bytes as a WHOLE rather then each as one in order to make it faster right? and if the address isnt a multiple of 8 its less efficent for some reason I dont understand lol
There's a little more to it than that, Anmol.

With modern processors, the CPU can access both even and uneven addresses. In general, accessing an even address is faster than accessing an uneven address.

Some data-types need to be aligned to a specific boundary. Let's assume we have a single "double" which is 8-bytes in length, which we will call "X".

If "X" is aligned to an 8-byte boundary, the CPU would be able to scoop up all of the bytes of "X" in one go. However, if "X" was not aligned to an 8-byte boundary, the CPU would most likely have to make two trips to memory to obtain all the bytes relating to "X" -- accessing memory is a time-consuming process, and to make an additional trip to memory is unnecessary workload.

In addition, accessing an uneven address adds to the CPU's workload further. Note that on some, older processors, accessing an uneven address could cause an hardware exception to be thrown which may not be taken too lightly by the operating system.

Wazzak
Last edited on
So basically if "X" was not aligned and half of it was in one 8-byte boundry and the rest was in another the CPU would have to make two trips to get all the memory?

Also what I said above was true right?

Thanks!
Also it only aligning here cause its a class? The largest data in the class is how big the boundary will be right?
> Also it only aligning here cause its a class?

No.

Any type other than char (and signed char, unsigned char) may have an implementation-defined alignment requirement.


> The largest data in the class is how big the boundary will be right?

No.

The alignment of a class object would be governed by the most stringent alignment requirement of its data members (including anonymous base class objects and hidden data members)

Read this first: http://www.ibm.com/developerworks/library/pa-dalign/

And then run this program and examine its output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <type_traits>
 
#define SHOW_SIZE_ALIGNMENT(T) ( std::cout << "type: " << #T << "  size: " \
          << sizeof(T) << "  alignment: " << std::alignment_of<T>::value << '\n' )
 
struct A { char cstr[103] ; };
struct B { int i[4] ; };
struct C { A a ; B b ; };
struct D { B b ; long long l ; };
 
int main()
{
    SHOW_SIZE_ALIGNMENT(char) ;
    SHOW_SIZE_ALIGNMENT(int) ;
    SHOW_SIZE_ALIGNMENT(long long) ;
    SHOW_SIZE_ALIGNMENT(char[25]) ;
    SHOW_SIZE_ALIGNMENT(int[3]) ;
    SHOW_SIZE_ALIGNMENT(A) ;
    SHOW_SIZE_ALIGNMENT(B) ;
    SHOW_SIZE_ALIGNMENT(C) ;
    SHOW_SIZE_ALIGNMENT(D) ;
}

Output (on a particular implementation):
type: char  size: 1  alignment: 1
type: int  size: 4  alignment: 4
type: long long  size: 8  alignment: 8
type: char[25]  size: 25  alignment: 1
type: int[3]  size: 12  alignment: 4
type: A  size: 103  alignment: 1
type: B  size: 16  alignment: 4
type: C  size: 120  alignment: 4
type: D  size: 24  alignment: 8

@JLBorges

What do you mean by stringent?

Also I already read that article and the example you showed, doesn't that example go with what I said?

The largest data type in the class determines its alignment?

If they did have implementation defined alignments would that mean that the sizeof operator may not reveal the correct size? So I doubt any compiler would want that to happen.

Also isn't the alignment set by the processor? Not by the compiler? So how does the compiler control this?
Registered users can post here. Sign in or register to post.