static global & compilation units

I want to see that my understanding of static keyword with regard to global variables is correct.

When there is a header file that defines a plain global variable, it is an error for two source files (compilation units?) to include this same header because of multiple definitions.

By using the 'static' modifier, separate variables will exist in each compilation unit that includes the header. But each compilation unit will only have access to its own local copy of the variable.

Correct?
By using the 'static' modifier, separate variables will exist in each compilation unit that includes the header. But each compilation unit will only have access to its own local copy of the variable.
Corrcet!
this is the same as declaring same static variable manualy in more *.cpp units. they are invisible to each other.

there are other static meanings:
static varibale inside a function lives as long as programs runs, it never dies.
static member inside a class lives as long as program is runing also.
static function is also local to *.cpp unit.
static member function lives as long as program runs and it may acces static varibales inside a class without an instance.

EDIT:
static has even more miining,
static linkage refers to variables which are invisible to other units.
these are constants and inline functions inside a header or cpp file.
while everything else is dinamyc liking.
note that static linkage is not the same as static varialbe!
Last edited on
I think what you are looking for is extern.

Declare the variable with extern in the header and define it in one source file without extern.

This does 2 things:
1) It turns the variable into a static variable (I think global variables are static by nature).
2) It tells the compiler to not worry when it can't find the definition of the variable. The linker will take care of this.
Declare the variable with extern in the header and define it in one source file without extern

It turns the variable into a static variable (I think global variables are static by nature).


you are a litle bit wrong with this one :/

that will define variable multiple times and make link time error(multiple defined objects) if header is being included multiple sources.
extern does not turn variable into static one.

extern is used to import variable from another cpp.


however if you declare it as extern const inside header this would not happen because const varialbes have internal linkage thus making it something like static.
codekiddy
Thanks for the note on static linkage. You could say that each static global variable has static linkage with respect to its own particular compilation unit?

Stewbond
So declaring an extern allows multiple compilation units to share a single global, as long as it is defined exactly once in just one of those source files.

Last edited on
Gladdok,
So declaring an extern allows multiple compilation units to share a single global.


No, you don't need keyword externd for that bahviour because that is default behaviour.

as I said in my previous post:
extern is used to import variable from another cpp.


making global inside a header will define variable multiple times and make link time error(multiple defined objects) if header is being included multiple sources.

however if you declare it as extern const inside header this would not happen because const varialbes have internal linkage thus making it something like static.

but anyway use of extern inside a header has no much sence since.
it has sence when you do not include a header file into all the *.cpp file but you want specific varilable to be vilible around whole project.
codekiddy, when you say:
"static member function lives as long as program runs"
correct me if I am wrong but normal member functions also live as long as the program run... The only difference is that static member functions can be called without an instance of the class
aquaz,
"static member function lives as long as program runs"

yes as long as program runs, thus it can be accesed without instance of an object.

non-static member function lives as long as an instance of object lives.(not as long as program runs)
that's not the same, since each object has it's own copy of non-static function.

however is an object lives as long as program does then member function of that object lives too.

1
2
3
4
5
//header.h
#ifndef HEADER_H
#define HEADER_H
int foo;
#endif 

1
2
3
4
5
6
7
//a.cpp
#include "header.h"
//b.cpp (yep, the same)
#include "header.h"
//main.cpp
#include "header.h"
int main(){}
$ g++ {a,b,main}.o
b.o: multiple definition of 'foo'
a.o: first defined here
main.o: multiple definition of 'foo'
a.o: first defined here
An include is the same as copy-paste.
If you want the variable to be shared, declare it extern. You need to define it somewhere.
If you want it to be local to the unit, declare it static

static members don't need instances to be accessed. So they can be thought as class properties.
codekiddy I think you are making a big (but common) mistake about how member functions work (i'm sure now).

Member fuctions exist only once in the program and objects only contains members variables. This code sample prove it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Test
{
public:
	Test(int parI) : m_i(parI) {}
	void apply(bool parT) // Here apply is not static because it uses member m_i
	{
		if (parT)
			std::cout << m_i;
		else
			std::cout << "0";
		std::cout << std::endl;
         }
private:
	int m_i;
};

int _tmain(int argc, _TCHAR* argv[])
{
	Test* t = NULL;
	t->apply(false);
	return 0;
}


This works fine even with t being null. Why? because there is no need to store functions in objects, this would be a huge waste of space. Try sizeof on Test, it will display 4, the size of member variable m_i.

Of couse you can't call virtual functions on NULL objects because it need the vtable pointer but it's the same, virtual functions are not in objects but in the vtable which is unique for each type.
Hi aquaz,
I'm not making mistake, if I do give some standard referecne and prove it.

This works fine even with t being null. Why?

because Test(int parI) : m_i(parI) {} is not just constructor, it is an converrsion operator too! (that means it will implicitly convert integer to bool)
because NULL == 0 == false your object is being created where member m_i is set to false.
0 if false, everything else is true (even negative numbers)
NULL is macro name for 0


virtual functions are stored in vtable and object in that case have v-pointer instead of function but that is not case in your example above.
Last edited on
because NULL == 0 == false your object is being created where member m_i is set to false.

I don't think so because t is a pointer in this case, have you noticed the star in Test* t = NULL;? So no conversion operator is called.

If you are still doubting, change line 4 with Test(int parI, int parUseless) : m_i(parI) {} so the constructor is not a conversion operator anymore. It still works with no runtime-errors.

The exemple i give is standard C++ so i think it is standard reference.

Sorry to insist but i think it is important to make it clear, it is one of the biggest misunderstandings made by a lot of C++ programmers.
aquaz,
have you noticed the star in Test* t = NULL;

lol no I didn't :D

I've been reading a litle bit about memberfunctions cos that was really interesting me...
so yeah, you had wright member functions are located in ONE part of memory means all the object's share same piece of function.

however non-static function can't be called without an object instance or more in other words there must exist this pointer to acces function or data)

now I'm confused here lol

how the hell is it possible to call function with no this pointer then? in this code:
1
2
Test* t = NULL;
t->apply(false);


I've been searching for this in C++ standard on openstd.org and in my book but nowere found an explanation of that :/

btw. thanks for puting this mistery out!!
how the hell is it possible to call function with no this pointer then? in this code:


Because 'this' is passed as a hidden parameter. If that parameter isn't used, then it's no problem.

1
2
3
4
5
6
7
// doing this...
Test* t = NULL;
t->apply(false);

// is conceptually similar to doing this:
Test* t = NULL;
Test_apply( t, false );


The function can be called, and a NULL pointer for 'this' provided. This will only be a problem if you attempt to dereference 'this' (ie: if the function is virtual, or if the function attempts to access any member variables).


Although while this is largely true in practice, the C++ standard doesn't say it has to be true. There is no guarantee that t->apply(false); will work with a null pointer. It's very possible for it to crap out on you, even if the function is non-virtual and doesn't access any members.
Last edited on
Right, it's undefined behaviour. Still, I doubt some weird compiler will try to dereference a this pointer if it's no use as C++ philosophy is to not doing things in you back.

I even seen code (I find it horrible, I agree) where there was something like this: if (this)....

But we all agree that we can't rely on such a trick in software development!
Last edited on
Topic archived. No new replies allowed.