name scope across files? extern, const etc.

To test the variable name's scope across files, I designed the following test project:

the project include 5 files: variable.h (used to declare the variables), function.h (used to declare the functions:giveValue() and printValue()), giveValue.cpp (giveValue() defined here), printValue.cpp (printValue() defined here), and main.cpp(will call giveValue() and then call printValue()).

The contents of each file are as follows:
variable.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef VARIABLE_H_
#define VARIABLE_H_

extern const int ec;
extern const int ecc=1+1;
//const int c;
const int cc=1+2;

extern int ei;
//int i;


#endif /* VARIABLE_H_ */ 


function.h:
1
2
3
4
5
6
7
8
#ifndef FUNCTION_H_
#define FUNCTION_H_

void giveValue();
void printValue();


#endif /* FUNCTION_H_ */ 


giveValue.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include "variable.h"
#include "function.h"

using namespace std;

void giveValue() {
	int sum(0), step;
	cin>>step;
	for(int i=0; i<step; i++) {
		sum+=i;
	}

 	ec=sum;

	ei=sum+1;

}


printValue.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include "variable.h"
#include "function.h"

using namespace std;

void printValue() {
	cout<<"ec"<<ec<<endl;
	cout<<"ecc"<<ecc<<endl;

	cout<<"cc"<<cc<<endl;
	cout<<"ei"<<ei<<endl;

}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include "variable.h"
#include "function.h"

using namespace std;

int main() {
	giveValue();
	printValue();
	return 0;
}


This one cannot be compiled, errors are: multi definition of ecc, undefined reference to ec and ei.

confused!

What I expect is:

1: ecc and cc are const definition, they will have their own copy of ecc and cc for each .cpp files, but their values will be the same, that is ecc=2 and cc=3.

2: ec is declared as const, and got it's initial value in giveValue() and then the value cannot be changed anymore, and when printValue, ec would print the value given by giveValue()

3: ei is variable, and get value from giveValue(), and print the same thing from printValue().

What am I wrong? Thanks.
Last edited on
Let's back up a bit...

This is easier to visualize with functions. So let's start there. Global variables work the exact same way.. and I'll explain those below.. so bear with me here.



When you create a function in a source file, that function is only declared in that source file. However the name of the function is externally linked so that other source files can link to it.

For example:

1
2
3
4
5
6
7
8
// a.cpp
#include <iostream>
using namespace std;

void func()
{
    cout << "func in a.cpp" << endl;
}

1
2
3
4
5
6
7
8
// b.cpp
#include <iostream>
using namespace std;

void func()
{
    cout << "func in b.cpp" << endl;
}



Try to link these 2 files together and you'll get a "multiple defined" linker error, because you have two different functions with the same name. If you call func(), which version are you intending to call? a.cpp's version or b.cpp's version?


Makes sense, right? So what if you move the function to a header file:

1
2
3
4
5
6
7
// header.h
#include <iostream>

void func()
{
    std::cout << "func in header.h" << std::endl;
}

1
2
// a.cpp
#include "header.h" 

1
2
// b.cpp
#include "header.h" 


Same problem here. But why? You only have one function, right? So why is it saying "multiple defined"?

Well, it's because #include basically works like a glorified copy/paste operation (it's more complex than that, but conceptually that's a good way to think of it). When you include header.h, you are effectively copy/pasting the entire contents of the header into this source file.

As a result... you have the same problem as illustrated above. Both a.cpp and b.cpp are including the header... so both are copy/pasting their own copy of func()... therefore func() has a body in multiple cpp files and the linker doesn't know which version you want to use. So it spits out that error.



There are a few ways to solve this problem. The most common is to make sure func() only exists in one cpp file. But still make it accessible in other cpp files by putting a prototype in a header file. Example:

1
2
3
4
5
6
// header.h

void func();  // a note for the compiler.  This does not actually create the function,
  // it just tells the compiler "func" is a function name... so it's OK to call it
  //  and the linker will have this function defined somewhere, so don't worry
  //  about it 


You can include this header in any number of files now without problem. The prototype does not actually create a function body, it's just a note to the compiler to allow the name 'func' to be recognized. You can then put that function body in one and only one cpp file, and the linker will tie it together with all other source files in the project.



Note however, that you need to actually put the body somewhere. If you don't put a function body somewhere in the code, you'll get "unresolved external symbol" errors from the linker. After all, how can you call a function that was never defined?



Hopefully that makes sense. Assuming it does....


Global variables are exactly the same.

int var;

This is the variable equivalent of a function body. You are creating a new variable, and reserving memory for it. So back to the original example:

1
2
3
//a.cpp

int var;

1
2
3
//b.cpp

int var;


This will give you multiple definition errors just like the function example did. You now have 2 variables with the same name, and the linker doesn't know which one you are intending to use.

Move 'var' to a header and #include it multiple places and it solves nothing... because #include just copy/pastes the definition into multiple files.



So to solve this... you need some way to make a "prototype"... similar to how you can have a function prototype that isn't actually a body, yet tells the compiler it's OK to treat "var" as a variable name... and tells the linker "don't worry, 'var' will be defined somewhere".

The way to do that with variables is the extern keyword:

 
extern int var;


This is like a "variable prototype". It does not actually define the variable. It's a note to the compiler saying "var is a variable name, but it's not defined here. It's defined elsewhere and the linker will fill it in for you."

So this is OK to #include in any number of source files. Each source file will not be creating their own copy of the variable... but will just be referencing a variable that will be externally linked by the linker.


But, as with functions, you still need to give the variable a "body". This means you have to define it (without extern) in one and only one source file. If you fail to do this, you will get unresolved external errors, just like you would if you don't give a function a body. After all.... how can you use a variable that was never defined?

So:

1
2
//header.h
extern int var;  // prototype the var 

1
2
// one_and_only_one_source_file.cpp
int var; // give it a body 



That's it. The const keyword is irrelevant to this topic and does not change this fundamental behavior.

The static keyword does... but that's another topic that I won't get into here (though if you're interested I can explain it).
Thanks, Disch, for all these inputs!!! I think I got the declare and definition thing now!

And thank you for remind me studying static keyword and const together.

I will do some test and let you know. Thanks again!!!
Last edited on
Thanks, Disch! I changed the program to this, and it solved all my problems:

variable.h:
1
2
3
4
5
6
7
8
9
10
11
#ifndef VARIABLE_H_
#define VARIABLE_H_

extern const int ec;
const int ecc=1+1;
//const int c;
const int cc=1+2;

extern int ei;

#endif /* VARIABLE_H_ */ 


function.h:
1
2
3
4
5
6
7
8
#ifndef FUNCTION_H_
#define FUNCTION_H_

void giveValue();
void printValue();


#endif /* FUNCTION_H_ */ 


giveValue.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include "variable.h"
#include "function.h"

using namespace std;

int value() {
	int sum(0);
	int step;
	cin>>step;
	for(int i=0; i<step; i++) {
		sum+=i;
	}

	return sum;
}

int ei;
void giveValue() {
	ei=value()+1;

}

const int ec=value(); //pickup the declared name- ec and define it and cannot be changed anymore 


printValue.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include "variable.h"
#include "function.h"

using namespace std;

void printValue() {
	cout<<"ec"<<ec<<endl;
	cout<<"ecc"<<ecc<<endl;

	cout<<"cc"<<cc<<endl;
	cout<<"ei"<<ei<<endl;

}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include "variable.h"
#include "function.h"

using namespace std;

int main() {
	giveValue();
	printValue();
	return 0;
}
Last edited on
Topic archived. No new replies allowed.