Tuesday, January 18, 2011

Pragma and It's Usage in C++

Pragma Pack:-

A pragma is a compiler directive that allows you to provide additional information to the compiler. This information can change compilation details that are not otherwise under your control. For example, the pack pragma affects the layout of data within a structure. Compiler pragmas are also called directives.
The preprocessor keyword pragma is part of the C++ standard, but the form, content, and meaning of pragmas is different for every compiler. No pragmas are defined by the C++ standard. Code that depends on pragmas is not portable.

Syntax:
#pragma pack [n]

Where n can equal 1, 2, 4, 8, or 16 and indicates, in bytes, the maximum alignment of class fields having non-class types. If n is not specified, maximum alignment is set to the default value.

Description:

This pragma allows you to specify the maximum alignment of class fields having non-class types. The alignment of the whole class is then computed as usual, the alignment of the most aligned field in the class.

NOTE: The result of applying #pragma pack n to constructs other than class definitions (including struct definitions) is undefined and not supported. For example:

The following example illustrates the pack pragma and shows that it has no effect on class fields unless the class itself was defined under the pragma.
Example 1:

struct S1 {
char c1; // Offset 0, 3 bytes padding
int i; // Offset 4, no padding
char c2; // Offset 8, 3 bytes padding
}; // sizeof(S1)==12, alignment 4

#pragma pack 1

struct S2 {
char c1; // Offset 0, no padding
int i; // Offset 1, no padding
char c2; // Offset 5, no padding
}; // sizeof(S2)==6, alignment 1

// S3 and S4 show that the pragma does not affect class fields
// unless the class itself was defined under the pragma.
struct S3 {
char c1; // Offset 0, 3 bytes padding
S1 s; // Offset 4, no padding
char c2; // Offset 16, 3 bytes padding
}; // sizeof(S3)==20, alignment 4

struct S4 {
char c1; // Offset 0, no padding
S2 s; // Offset 1, no padding
char c2; // Offset 7, no padding
}; // sizeof(S4)==8, alignment 1

#pragma pack

struct S5 { // Same as S1
char c1; // Offset 0, 3 bytes padding
int i; // Offset 4, no padding
char c2; // Offset 8, 3 bytes padding
}; // sizeof(S5)==12, alignment 4

Thursday, January 13, 2011

Memory Layout of Empty Class, Simple class, Derived Class, Class with Virtual Function

Here I am going to tell different memory layout of a class of different types in C++.
Like Empty Class, Simple Class having non-static data members and functions, Class having static data members and functions, Derived Class, Class having Virtual Functions and so on. Also I am going to explain How Virtual table, Virtual pointer for Virtual functions are internally working.

Example 1) Empty Class
class Test
{
};
main()
{
Test obj;
cout << "obj's Size = " << sizeof(obj) << endl;
}
Output:
Sobj's Size = 1 //minimum memory required for the entry of the class in the symbol table.

Example 2) Simple Class with static data members and function's memory layout
class Test
{
public:
static int data;
int data;
};

main()
{
Test obj;
cout << "obj's Size = " << sizeof(obj) << endl;
}

Output:
Sobj's Size = 4//Size of 'int' data type is 4bytes only, not the static data member

Example 3) Simple Class with non-static data members and function's memory layout
class Test
{
public:
int data;
int fun1();
};
main()
{
Test obj;
cout << "obj's Size = " << sizeof(obj) << endl;
}

Output:
Sobj's Size = 4//Size of 'int' data type is 4bytes

Note: Any Plane member function does not take any memory.


Example 4: Memory Layout of Derived class
class Test
{
public:
int a;
int b;
};
class dTest : public Test
{
public:
int c;
};
main()
{
Test obj1;
cout << "obj1's Size = " << sizeof(obj1) << endl;
dTest obj2;
cout << "obj2's Size = "<< sizeof(obj2) << endl;
}

OUTPUT:
obj1's Size = 8
obj2's Size = 12

Example 5: Memory layout If we have one virtual function.
class Test
{
public:
int data;
virtual void fun1()
{
cout << "Test::fun1" << endl;
}
};
main()
{
Test obj;
cout << "obj's Size = " << sizeof(obj) << endl;
}

OUTPUT:
obj's Size = 8//size of one data member and a pointer for virtual function

Note: Adding one virtual function in a class takes 4 Byte extra.

Example 6: More than one Virtual function
class Test
{
public:
int data;
virtual void fun1() { cout << "Test::fun1" << endl; }
virtual void fun2() { cout << "Test::fun2" << endl; }
virtual void fun3() { cout << "Test::fun3" << endl; }
virtual void fun4() { cout << "Test::fun4" << endl; }
};
main()
{
Test obj;
cout << "obj's Size = " << sizeof(obj) << endl;
}

OUTPUT:

obj's Size = 8

Note: Adding more virtual functions in a class, no extra size taking i.e. Only one machine size taking(i.e. 4 byte)

Example 7: Priority of a Virtual Function in a Class Layout in C++
class Test
{
public:
int a;
int b;
Test(int temp1 = 0, int temp2 = 0)
{
a=temp1;
b=temp2;
}
int getA()
{
return a;
}
int getB()
{
return b;
}
virtual ~Test();
};
main()
{
Test obj(5, 10);
// Changing a and b
int* pInt = (int*)&obj;
*(pInt+0) = 100;
*(pInt+1) = 200;
cout << "a = " << obj.getA() << endl;
cout << "b = " << obj.getB() << endl;
}

OUTPUT:
a = 200
b = 10

If we Change the code as then

// Changing a and b
int* pInt = (int*)&obj;
*(pInt+1) = 100; // In place of 0
*(pInt+2) = 200; // In place of 1

OUTPUT:
a = 100
b = 200

Note: Who sits 1st place of Class : Answer is VPTR
VPTR - 1st placed in class and rest sits after it.

Example 8:
class Test
{
virtual void fun1()
{
cout << "Test::fun1" << endl;
}
};
main()
{
Test obj;
cout << "VPTR's Value " << (int*)*(int*)(&obj+0) << endl;
}

OUTPUT:

VPTR's Value 0046C060

NOTE: This VPTR's value is a address of Virtual table. Lets see in next Example.

Example 9: Virtual Function with Function Pointer in C++

class Test
{
virtual void fun1()
{
cout << "Test::fun1" << endl;
}
};
typedef void (*Fun)(void);
main()
{
Test obj;
cout << "VPTR's Address " << (int*)(&obj+0) << endl;
cout << " VIRTUAL TABLE 's Address " << (int*)*(int*)(&obj+0) << endl; // Value of VPTR
cout << "Value at first entry of VIRTUAL TABLE " << (int*)*(int*)*(int*)(&obj+0) << endl;

Fun pFun = (Fun)*(int*)*(int*)(&obj+0); // calling Virtual function
pFun();
}

OUTPUT:
VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Test: fun1