Recently I was reviewing C++ . And I was interested in TYPEOF , this operator . You can use it Like " sizeof( testedVariable ) " to see the size of testedVariable . You might think it is a function . But it is not . it is a operator , not a function . So don't mess it . But I wondered how it works . I mean sometimes the result comes I don't understand . ex:
#include <iostream>
using namespace std;
struct myStruct {
char a;
int b;
};
int main() {
cout<<sizeof(myStruct); // the result is 8(in 64 bit) , not 5 !
cout<<endl;
return 0;
}
So I dug something about it . Turns out , it has rules to calculate . NOT just add them together . But I will start form the simple part .
First , the basic data types . We both know that int type takes 4 bytes in 64 bit CPU , and takes 2 bytes in 32 bit CPU . Let's talk about the differences between the 32 bit CPU and 64 bit CPU . For the data type , only two data types , int and pointer , are different .
data type | int | short | long | char | float | double | long double | pointer |
32 bit | 2 | 2 | 4 | 1 | 4 | 8 | 8 | 4 |
64 bit | 4 | 2 | 4 | 1 | 4 | 8 | 8 | 8 |
So , the basic data types :
Here it is , I think most of them you would understand , except for the last three lines . The results of the last three lines , depend the values, AKA , the strings . So , now you see .int intType = 0; short shortType = 0; long longType = 0; char charType = 'c'; float floatType = 0.1; double doubleType = 1.0; long long longlongType = 1; int *intPointer; char *stringPointer = "Hello World"; char arrayStringPointer[] = "Hello World"; cout<<"intType : "<<sizeof( intType )<<endl; // 4 cout<<"shortType : "<<sizeof( shortType )<<endl; // 2 cout<<"longType : "<<sizeof( longType )<<endl; // 8 cout<<"charType : "<<sizeof( charType )<<endl; // 1 cout<<"floatType : "<<sizeof( floatType )<<endl; // 4 cout<<"doubleType : "<<sizeof( doubleType )<<endl; // 8 cout<<"longlongType : "<<sizeof( longlongType )<<endl; // 8 cout<<"intPointerType : "<<sizeof( intPointer )<<endl; // 8 cout<<"stringPointerType : "<<sizeof( stringPointer )<<endl; // 8 cout<<"stringType : "<<sizeof( "Hello World" )<<endl; // 12
cout<<"another stringType : "<<sizeof( "Hello World ! " )<<endl; // 15
cout<<"arrayStringPointerType : "<<sizeof( arrayStringPointer )<<endl; // 12
Next , the struct . First , let's back to the first example I wrote and think about it . Why ? So , it has one rule about " align in CPU " thing . It means that the sizeof will just calculate integral multiple sizes . It means that the result must be the integral multiple of 4 , well , in 64 bit . So it will be different when you change the order of the properties . Because it will add bytes till the offset of CPU is the integral multiple of the next property's type . For example , the first property is int type , the second property's type is char . In the beginning , the offset is 0 , and it will be 4 when comes the first property . and then the second comes , it will check the offset now is the integral multiple of the number of bytes this property takes or not . If it is not , it will add bytes to let the offset be the integral multiple of 4 . And go on by this rule . Hope you understand . Let's see the demo :
struct emptyStruct {
};
struct firstStruct {
char a;
};
struct secondStruct {
char a;
int b;
char c[17];
int d;
};
int main() {
cout<<"emptyStruct : "<<sizeof( emptyStruct )<<endl; // 1
cout<<"firstStruct : "<<sizeof( firstStruct )<<endl; // 1
cout<<"secondStruct : "<<sizeof( secondStruct )<<endl; // 32
cout<<endl;
return 0;
}
So you see , empty struct takes 1 . And this is not weird , because it is a empty pointer , for us to get it .
Then , class . It is almost the same as above . Let's see the code first :
class emptyClass {
};
class staticClass {
public:
static int a;
};
class functionClass {
public:
int a();
};
class normalClass {
public:
normalClass();
~normalClass();
void d();
private:
int a;
char b;
static char c;
};
class normalClassWithVirtualFunction {
public:
normalClassWithVirtualFunction();
~normalClassWithVirtualFunction();
void virtual d();
private:
int a;
char b;
static char c;
};
class parentClass {
public:
parentClass();
~parentClass();
void d();
private:
int a;
char b;
float c;
static char e;
};
class subClass : public parentClass {
public:
subClass();
~subClass();
void f();
private:
int a;
char b;
float c;
static char e;
};
int main() {
cout<<"emptyClass : "<<sizeof( emptyClass )<<endl; // 1
cout<<"staticClass : "<<sizeof( staticClass )<<endl; // 1
cout<<"functionClass : "<<sizeof( functionClass )<<endl; // 1
cout<<"normalClass : "<<sizeof( normalClass )<<endl; // 8
cout<<"normalClassWithVirtualFunction : "<<sizeof( normalClassWithVirtualFunction )<<endl; // 16
cout<<"parentClass : "<<sizeof( parentClass )<<endl; // 12
cout<<"subClass : "<<sizeof( subClass )<<endl; // 24
return 0;
}
As you see , the empty class , the class with static properties and the class with function , all take one byte in CPU . Because even if the classes have not their own properties , well not static , but we still need to ID them , means that we need to get them somehow , and this is how , we give them a pointer . And the normal classes , well , not so special , just like struct . We just count the size of the super class to the subclass .
Finally , the virtual inherit class . As we know , the subclass will create a virtual function class when it is virtual inherit form the super class . AKA , a pointer , means takes 8 bytes in 64 bit CPU . And it is not like struct , in this case , the CPU will give the class 8 bytes each time , in 64bit CPU which means the result is integral multiple of 8 . Let's see the code :
class parentClassWithoutVirtualFunc {
public:
parentClassWithoutVirtualFunc();
~parentClassWithoutVirtualFunc();
void d();
private:
int a;
};
class parentClassWithVirtualFunc {
public:
parentClassWithVirtualFunc();
~parentClassWithVirtualFunc();
void virtual d();
};
class subClass1 : public virtual parentClassWithoutVirtualFunc {
public:
subClass1();
~subClass1();
private:
int a;
char b;
float c;
};
class subClass2 : public virtual parentClassWithoutVirtualFunc {
public:
subClass2();
~subClass2();
private:
char a[15];
};
class subClass3 : public virtual parentClassWithoutVirtualFunc {
public:
subClass3();
~subClass3();
private:
char a[23];
};
int main() {
cout<<"parentClassWithoutVirtualFunc : "<<sizeof( parentClassWithoutVirtualFunc )<<endl; // 4
cout<<"parentClassWithVirtualFunc : "<<sizeof( parentClassWithVirtualFunc )<<endl; // 8
cout<<"subClass1 : "<<sizeof( subClass1 )<<endl; // 24
cout<<"subClass2 : "<<sizeof( subClass2 )<<endl; // 32
cout<<"subClass3 : "<<sizeof( subClass3 )<<endl; // 40
return 0;
}
So , there it is . Hope it will help you . And for the record , it is true on 64 bit CPU . Well you can try in 32 bit CPU .