Reputation: 24851
When programming, I would like to split one large file(which contains main function) to many small files, so there is one common case: functions in small files can modify the var from main file, so i think extern is very useful!
for instance:
in main.c
extern int i = 100;
in small.c
extern int i;
fprintf(stdout, "var from main file: %d\n", i);
I just want to know is my understanding right?
Upvotes: 2
Views: 497
Reputation: 95489
Yes, it is possible. However, instead of doing:
// moduleA.c
int c = 5;
void bar(void);
void foo(void) {
// ...
bar();
// ...
}
// moduleB.c
extern int c; // references "c" defined in moduleA
void bar(void) {
// ...
// do something with c
// ...
}
It is almost always better to do:
// moduleA.c
int c = 5;
void bar(int);
void foo(void) {
// ...
bar(c);
// ...
}
// moduleB.c
void bar(int c) {
// ...
// do something with c
// ...
}
In other words, while you can use global variables, passing variables explicitly as parameters is much better design. Please read Global Variables are Bad for a variety of reasons to avoid global variables. To highlight a few reasons why globals are bad:
They hide dependencies. For example, when your code references the global variable "c", the developer needs to hunt all over the place to find where it is defined and how it is used, since this variable can be modified by any module at all. In other words, it introduces unnecessary complexity.
Global variables are shared by the entire process. Whereas a local variable that is passed around would be created on a stack, and each thread has its own stack, globals share common storage for the entire program. Any function that uses a global variable (unless that global is a constant) is non-reentrant and, unless it locks access to that global variable, is not thread-safe. It is incredibly difficult to make a program that uses global variables thread-safe, and the fact that any module can write to a global variable means it is hard to ensure that all modules that write to the variable lock it.
Upvotes: 2
Reputation: 25739
You would have to change one thing to make it work: extern int i = 100;
in main.c should be changed to int i = 100;
Even if it's possible to do like this, I don't think it is a good design. The things you extract to separate files should be possible to use on their own, without any knowledge of what is inside main.c
.
An useful strategy for this kind of refactoring: First move the data, then move the functions that use that data. That is, first move the i
variable to small.c
, then move the functions that use i
.
If you want to move functions but not the data, try to pass i
as an argument instead of accessing it using extern
declaration.
Upvotes: 6
Reputation: 891
One file must contain the actual "concrete" int:
int i = 100;
All other files should contain an "external" reference to the int:
extern int i;
The linker shall then ensure that they all point to the same memory location.
Upvotes: 1
Reputation: 993015
You're almost there. You need to use just:
int i = 100;
in main.c
, otherwise you'll get a linker error.
The extern
declaration tells the compiler not to allocate space for that variable, but that the variable will be declared somewhere else. The compiler adds an "external reference" to the .o
file that tells the linker to connect up the references to the same variable.
Without letting the compiler create an actual instance of the i
variable, as you've done in your question, the linker will see all the external references to i
but not a definition of i
. The linker will want to see exactly one definition of every variable and function.
Upvotes: 1