Dive into Static Variable in C++: A Comprehensive Study

Introduction

I’ve often found myself using static variables a lot during my journey as a programmer. They are a convenient tool to have under your belt if you want a variable that should be shared across multiple objects or functions and rarely changes. Of course, like anything in C++, there might be some pitfalls when using these static variables and functions. The purpose of this post is to take a deep-dive into the world of static variable in C++.
This post will be iterative. I’ll keep updating here whenever I come across anything interesting related to static variables and functions.
For code demonstration, I’ll be using VSCode and MSVC compiler.

Organization of static variables and functions in code

To make the best of this section, I suggest downloading the Code Listing file for the code snippet below. This is generated by MSVC by giving compiler flags “/FAcsu”.

To make the best of this section, I suggest downloading the Code Listing file for the code snippet below. This is generated by MSVC by giving compiler flags “/FAcsu”.
The code for the code listing above is as follows:

#include<iostream>
// 1. Initialized static variable
static const int a = 100;
// 2. Un-Initialized static variable
static int unB;

// 3. Normal function with static variable
int* getFunctionStaticValRef()
{
    static int c = 300;
    return &c;
}

//4. Static function with static variable
static int* staticFunctionWithStaticVar()
{
    static int staticValInStaticFunc = 700;
    return &staticValInStaticFunc;
}

//5. Static function with normal variable
static int* staticFuncWithNormalVar()
{
    int normalVar = 800;
    return &normalVar; // This is just wrong! Please don't do this.
}


class ClassA
{
public:
    //6. 
    static int m_a;

    //7. 
    int* staticInNonStaticClassFunc()
    {
        static int unInitstaticVar;
        return &unInitstaticVar;
    }
    //8. 
    static int* staticInStaticClassFunc()
    {
        static int staticVar = 900;
        return &staticVar;
    }
};
int ClassA::m_a = 400;

template<typename T>
class TemplateClass
{
public:
    //9. 
    static int m_t_a;

    //10. 
    int* staticInNonStaticTemplateClassFunc()
    {
        static int staticVar = 1000;
        return &staticVar;
    }
    //11. 
    static int* staticInStaticTemplateClassFunc()
    {
        static int staticVar = 1100;
        return &staticVar;
    }
};
int TemplateClass<int>::m_t_a = 1100;

int main()
{
    //Static tests
    const int* refA = &a;
    int* refB = &unB;

    int* heapAlloc1 = new int(10);
    int* heapAlloc2 = new int(10);

    int* refC = getFunctionStaticValRef();
    
    int* heapAlloc3 = new int(10);
    int* heapAlloc4 = new int(10);
    
    const int* ref_staticValInStaticFunc = staticFunctionWithStaticVar();
    
    const int* ref_staticWithNormalVar = staticFuncWithNormalVar();

    ClassA* heapObj = new ClassA();
    int* ref_mA = &ClassA::m_a;

    const int* ref_staticInNonStaticClassFunc = heapObj->staticInNonStaticClassFunc();
    const int* ref_staticInStaticClassFunc = ClassA::staticInStaticClassFunc();

    TemplateClass<int>* heapObj2 = new TemplateClass<int>();
    int* ref_t_mA = &TemplateClass<int>::m_t_a;

    const int* ref_t_staticInNonStaticClassFunc = heapObj2->staticInNonStaticTemplateClassFunc();
    const int* ref_t_staticInStaticClassFunc = TemplateClass<int>::staticInStaticTemplateClassFunc();

    return 0;
}

Let’s first establish a couple of things. Static variables are basically global variables and have their memory allocated during their declaration.

  • An Un-Initialized static variable is created in the DATA_SEGMENT of the assembly code.
  • An Initialized static variable is created in the BSS_SEGMENT of the assembly code.
  • Since program stack grows from lower to higher memory address, static variables ALWAYS occupy a lower memory address than any heap allocated variable. For a quick overview of the Data segment, please refer to this wiki post

Let’s break apart the code snippet and how the code is arranged for static functions and variables. To make the best of this, refer to the CodeList file provided and check how the code is arranged:

  1. This is an initialized static variable and occupies DATA segment. DATA segment is usually setup before the CODE/TEXT segment starts.
  2. An un-initialized static variable and this occupies BSS segment.
  3. Static variable in a normal function also gets created in the DATA segment if it’s initialized or in BSS if it’s uninitialized.
  4. This is identical to 3. Since the function is global, marking it as static doesn’t really make much of a difference.
  5. Returning address of a temporary variable is always bad. Even if that’s inside a static function. NEVER DO THIS!
  6. Now, this one’s a static variable inside a class. Now, if you see the code listing file, you can notice that this sits right in the DATA segment and basically has a global scope (with the class name and any additional namespaces considered, of course).
  7. This one’s a static variable inside a non-static member function. The variable still occupies the DATA segment as expected.
  8. We now have a static variable inside a static member function.
    The difference between static and normal member functions is that, normal member functions must obtain the pointer to the object that’s calling it. While, static functions doesn’t have to do that.
    In the code lists file, we can see that the normal member function has these additional instructions to store the object that’s calling the function:
    push ecx
    mov DWORD PTR _this$[ebp], ecx
  9. This one’s a static variable inside the template class. Now, I have not initialized this variable, just defined it so that the linker doesn’t complain. As expected, this variable occupies the BSS segment.
  10. Behavior is identical to 7.
  11. Behavior is identical to 8.
Declaring and Defining A Static variable

Still working on this section. Please check back later.

That is all for this post and I hope this has been useful.
Please do visit again 🙂


Leave a Reply

Your email address will not be published. Required fields are marked *