Compiler outputting wrong size

Pages: 123
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.
closed account (zb0S216C)
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".
closed account (zb0S216C)
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
closed account (zb0S216C)
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?
> doesn't that example go with what I said?
> The largest data type in the class determines its alignment?

No.

For instance, examine class C
struct C { A a ; B b ; };

The member a has a size of 103, and has no alignment requirement (1).

The member b has a (smaller) size of 16, but has (a more stringent) alignment requirement of 4.

sizeof(C) >= sizeof(A) + sizeof(B)

alignment of(C) == 4 (which is maximum of (more stringent of) ( alignment of(A), alignment of(B) ) )


> would that mean that the sizeof operator may not reveal the correct size?

The sizeof operator will always yield the correct size (the number of bytes an object of that type occupies).

std::alignment_of<> will always yield the correct alignment requirement for an object of that type.

However, the alignment requirement for an object with a smaller size may be more stringent (have a larger value) than that of an object with a bigger size. Size and alignment are not dependant on each other; they are orthogonal. An array of a million char char[1000000] has a big size, and also has the least stringent alignment requirement. An int may have a much smaller size than the 1MB array, but may (usually does) have a more stringent alignment requirement.



> Also isn't the alignment set by the processor? Not by the compiler?
> So how does the compiler control this?

The alignment is defined by the implementation (compiler) based on what is required by (or is more optimal) for the particular target processor architecture.
For instance, the alignment requirements defined by GCC for i386/Windows would be different from the alignment requirements defined by GCC for mips64.
Last edited on
What do you mean by stringent.

Also what you are saying is EXACTLY what I meant. It depends on the TYPE of data's size not the total size lol.
Also small side question.

In a base class with all its members either private or protected, that will not be changed if its derived class inherits via public right, at least in the derived class?

But if in the base class all its members are public, this can be changed if the if its derived class inherits via protected or private right, at least in the derived class?
> Also what you are saying is EXACTLY what I meant.

What I'm saying is exactly contrary to what you meant.

Even if you do not believe that char[1000000] is a type (it is), or that struct B is a type (it too is), try this on a particular implementation:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <type_traits>
 
#define SHOW_SIZE_ALIGNMENT(T) ( std::cout << "type: " << #T << "  size: " \
          << sizeof(T) << "  alignment: " << std::alignment_of<T>::value << '\n' )
 
int main()
{
    SHOW_SIZE_ALIGNMENT(double) ; // size 8, alignment 8
    SHOW_SIZE_ALIGNMENT(long double) ; // size 12, alignment 4
}


http://ideone.com/dPK32Z

> Also small side question.

Not very clear to me what you meant by that. Perhaps you could illustrate the question with an example.
Pages: 123