28

I know that this program is not using the static variable in an appropriate way, but it shows how to reproduce a behavior I have seen :

Main.cpp :

int main(){
    MyObject* p = new MyObject();
    Header::i = 5;

    printf("i %i\n", Header::i);
    p->update();

    return 0;
}

MyObject.cpp :

MyObject::MyObject(){
}

void MyObject::update(){
    printf("i %i\n", Header::i);
}

Extern.h :

namespace Header {
    static int i;
};

The output I get is :

i : 5
i : 0

Why don't I get 5 for both outputs ? Where does this 0come from ? Could you explain how static variables work ?

random
  • 10,238
  • 8
  • 57
  • 101
Arcyno
  • 4,153
  • 3
  • 34
  • 52
  • 3
    Consider how `#include` works, and what `static` means for non-local non-member variables. – user253751 Jun 25 '15 at 09:46
  • 2
    You should also post the `#include`s in each cpp file, so to make it clear that you are including `Extern.h` in two cpp files, hence creating two variables `i`. – chi Jun 25 '15 at 14:28
  • Did you used [include guards](https://en.wikipedia.org/wiki/Include_guard)? – ST3 Jul 21 '15 at 13:21

8 Answers8

51

Static variables have internal linkage which effectively means they are local to the compilation unit. Since you have the static variable declared in a header included in 2 source files, you basically have 2 distinct variables: one i local to MyObject.cpp and another, different i, local to main.cpp

bolov
  • 72,283
  • 15
  • 145
  • 224
  • That's very interesting ! If I wanted to use it as a "real" global variable, what should be done ? – Arcyno Jun 25 '15 at 09:07
  • 19
    don't use `static`. Use `extern` in header with initialization in a single source file. But global variables should be avoided like plague. – bolov Jun 25 '15 at 09:09
13

You have one static variable per translation unit where you include the header, because static variables have internal linkage.

Where does this 0 come from ?

You've not initialized the variable in the second translation unit, and static variables are zero-initialized, that's where the 0 comes from.

In the standard (§3.6.2/2):

Variables with static storage duration (3.7.1) [...] shall be zero-initialized (8.5) before any other initialization takes place.[...]

JBL
  • 12,588
  • 4
  • 53
  • 84
12

You have two variables i

static int i;

because it has internal linkage. That means that each compilation unit where the corresponding header was included has its own object i and other compilation units know nothing about presnece of that object in this compilation unit.

If you will remove specifier static then the linker should issue a message that the variable is defined twice.

The same effect can be achieved if to place a variable in an unnamed namespace in C++ 2011. For example instead of

namespace Header {
    static int i;
};

you could write

namespace {
    int i;
};

In this case varaible i also has internal linkage. This is valid for C++ 2011.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
9

You should not put static valiables in header files. That leads to every cpp file that includes that header to have a copy of that static local to its compilation unit.

What you could do is extern storage specifier:

Header:

namespace Header {
    extern int i;
}

Cpp:

namespace Header {
    int i = 0;
}
Alexander Balabin
  • 2,055
  • 11
  • 13
7

As an addition to the all the answers. WHY it happens, was already explained. However HOW to fix it, was suggested till now only by using static/extern approach. This is little bit C-like. Unles you don't have to use the header in C-part of the project with C-linkage, you could use C++.

So IF you have really to use something static in your code.

Either declare the variable as a member of a class:

header.h

MyGlobalVariableHoler
{
  public: static int i;
};

main.cpp

// class' statics have has to be initialized, otherwise linker error.
int MyGlobalVariableHoler::i=0;

any_code.cpp

#include <header.h>

MyGlobalVariableHolder::i=4711;

Or use a singleton to avoid the explicit initialization

header.h

MyGlobalVariableHolder
{
    MyGlobalVariableHolder(){i=0;}
  public:
    static MyGlobalVariableHolder & instance()
    {
       static MyGlobalVariableHolder inst;
       return inst;
    }
    int i;
};

any_code.cpp

#include <header.h>
MyGlobalVariableHolder::instance().i=4711;
Valentin H
  • 7,240
  • 12
  • 61
  • 111
  • Why would that be better that just : `extern in i;` in the header, and then a real declaration inside main.cpp `int Header::i = 0;` ? – Arcyno Jun 25 '15 at 09:41
  • Do you mean the singleton approach? Here the static is a local function's static. It is always initialized before you call instance() first time. Global statics may be not initialized. – Valentin H Jun 25 '15 at 11:26
5

Its better to declare your variable with extern in your header file to specify that it has an external linkage. Otherwise the above behavior will occur or potential compile or link problems can happen.

static int i ; // i has internal linkage
extern int i ; // i has external linkage
Identity1
  • 1,139
  • 16
  • 33
4

You are getting confused with class level static variable with namespace level static variable. Both are accessed by X::y qualification, adding to confusion. Others have explained actual reason (at the compilation/linkage level).

Ajay
  • 18,086
  • 12
  • 59
  • 105
3

The variable that is declared static only has scope in the file in which it is declared where as the variable declared without static can be accessed from other files using an extern declaration.