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 typeint short longcharfloatdoublelong double pointer32 bit2241488464 bit 42414888
So , the basic data types :
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 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 .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 .
