Wednesday, February 2, 2011

How to use #pragma init_seg to Control Static Construction

Tip - In the Microsoft C++ Compiler, it is possible to control when your static objects, declared at file scope, are constructed and destructed by using the #pragama init_seg preprocessor directive.

Details - There are four options for the init_seg preprocessor directive.  In source code, this directive would have the form:

   #pragma init_seg(compiler)
   #pragma init_seg(lib)
   #pragma init_seg(user)
   #pragma init_seg("user_defined_segment_name")

Only one init_seg directive can appear in a single source file. Otherwise, the compiler generates "error C2356.

The purpose of this directive is to give the developer the ability to group the constructors in an application. This would be useful if some objects relied upon the existence of other objects to function correctly[static initialization order fiasco].

Objects that are grouped together using #pragma init_seg(compiler) are constructed before all other objects and destroyed after all other objects in the application. This is used for objects in the run-time libraries.

Objects that are grouped together using #pragma init_seg(lib) are constructed after and destructed before objects that are in modules compiled with #pragma init_seg(compiler), but before all other objects in the application.

Objects that are grouped together using #pragma init_seg(user) are constructed after and destructed before objects that are in modules compiled with #pragma init_seg(compiler) and #pragma init_seg(lib). In other words, objects that are grouped together using #pragma init_seg(user) are constructed and destructed at the same time as all other static objects that were not grouped using #pragma init_seg.

The #pragma init_seg("user_defined_segment_name") preprocessor directive puts the addresses of the constructors into the logical segment "user_defined_segment_name". This option is useful only if you modify the startup code to call these constructors.

The following code sample (four source files) demonstrates the above ideas. After compiling all source files, link them in the two ways shown below and run the resultant executables. The output from each will show which init_seg options are dependent on link order and which are not.

With Visual C++ 32-bit Edition versions, use:

   link file1 file2 file3 file4 /out:demo1.exe
  link file4 file3 file2 file1 /out:demo2.exe

With Visual C++ 16-bit versions, use:

   link file1 file2 file3 file4, demo1;
   link file4 file3 file2 file1, demo2;

Sample Code

// file1.cpp
// command line: cl /c file1.cpp
#pragma init_seg(compiler)
#include<stdio.h>
class MyCompClass
{
public:
      MyCompClass(){ printf("In the ctor of MyCompClass\n");}
      ~MyCompClass(){ printf("In the dtor of MyCompClass\n");}
} MyComp;

// file2.cpp
// command line: cl /c file2.cpp
#pragma init_seg(lib)
#include<iostream.h>
class MyLibClass
{
public:
      MyLibClass(){cout<<"In the ctor of MyLibClass"<<endl;}
      ~MyLibClass(){cout<<"In the dtor of MyLibClass"<<endl;}
} MyLib;

// file3.cpp
// command line: cl /c file3.cpp
#pragma init_seg(user)
#include<iostream.h>
class MyUserClass
{
public:
      MyUserClass(){cout<<"In the ctor of MyUserClass"<<endl;}
      ~MyUserClass(){cout<<"In the dtor of MyUserClass"<<endl;}
} MyUser;

// file4.cpp
// command line: cl /c file4.cpp
#include<iostream.h>
class MyRegularClass
{
public:
      MyRegularClass(){cout<<"In the ctor of MyRegularClass"<<endl;}
      ~MyRegularClass(){cout<<"In the dtor of MyRegularClass"<<endl;}
} MyRegular;

void main(){}

Reference   -

Posted By : Ajesh P.S

No comments:

Post a Comment