Thursday, July 25, 2013

c++ extern

From:http://www.gamedev.net/page/resources/_/technical/general-programming/organizing-code-files-in-c-and-c-r1798

When the linker comes to create an executable (or library) from your code, it takes all the object (.obj or .o) files, one per translation unit, and puts them together. The linker's main job is to resolve identifiers (basically, variables or functions names) to machine addresses in the file. This is what links the various object files together. The problem arises when the linker finds two or more instances of that identifier in the object files, as then it cannot determine which is the 'correct' one to use. The identifier should be unique to avoid any such ambiguity. So how come the compiler doesn't see an identifier as being duplicated, yet the linker does?

Imagine the following code:

/* Header.h */
#ifndef INC_HEADER_H
#define INC_HEADER_H
int my_global;
#endif /* INC_HEADER_H */

/* code1.cpp */
#include "header1.h"
void DoSomething()
{
 ++my_global;
}

/* code2.cpp */
#include "header1.h"
void DoSomethingElse()
{
 --my_global;
}
 
This first gets compiled into two object files, probably called 
code1.obj and code2.obj. Remember that a translation unit contains full 
copies of all the headers included by the file you are compiling. 
Finally, the object files are combined to produce the final file.
 
Notice how there are two copies of "my_global" in that final block. 
Although "my_global" was unique for each translation unit (this would be
 assured by the use of the inclusion guards), combining the object files
 generated from each translation unit would result in there being more 
than one instance of my_global in the file. This is flagged as an error,
 as the linker has no way of knowing whether these two identifiers are 
actually  same one, or if one of them was just misnamed and they were 
actually supposed to be 2 separate variables. So you have to fix it.

The
 answer is not to define variables or functions in headers. Instead, you
 define them in the source files where you can be sure that they will 
only get compiled once (assuming you don't ever #include any source 
files, which is a bad idea for exactly this reason). This gives you a 
new problem: how do you make the functions and variables globally 
visible if they aren't in a common header any more? How will other files
 "see" them? The answer is to declare the functions and variables in the
 header, but not to define them. This lets the compiler know that the 
function or variable exists, but delegates the act of resolving the 
address to the linker.  

To do this for a variable, you add the keyword 'extern' before its name:
extern int my_global;The 'extern' specifier is like telling the compiler to wait until link time to resolve the 'connection'. And for a function, you just put the function prototype:

int SomeFunction(int parameter);Functions are considered 'extern' by default so it is customary to omit the 'extern' in a function prototype.

Of course, these are just declarations that my_global and SomeFunction exist somewhere. It doesn't actually create them. You still have to do this in one of the source files, as otherwise you will see a new linker error when it finds it cannot resolve one of the identifiers to an actual address. So for this example, you would add "int my_global" to either Code1.cpp or Code2.cpp, and everything should work fine. If it was a function, you'd add the function including its body (ie. the code of the function) into one of the source files.

The rule here is to remember that header files define an interface, not an implementation. They specify which functions, variables, and objects exist, but it is not responsible for creating them. They may say what a struct or class must contain, but it shouldn't actually create any instances of that struct or class. They can specify what parameters a function takes and what it returns, but not how it gets the result. And so on. This is why the list of what can go into a header file earlier in this article is important.
 

No comments:

Post a Comment