Professional C__ - Marc Gregoire [143]
void f();
int main()
{
f();
return 0;
}
Code snippet from Static\FirstFile.cpp
Note that this file provides a prototype for f(), but doesn’t show the definition.
Here is AnotherFile.cpp:
#include using namespace std; void f(); void f() { cout << "f\n"; } Code snippet from Static\AnotherFile.cpp This file provides both a prototype and a definition for f(). Note that it is legal to write prototypes for the same function in two different files. That’s precisely what the preprocessor does for you if you put the prototype in a header file that you #include in each of the source files. The reason to use header files is that it’s easier to maintain (and keep synchronized) one copy of the prototype. However, for this example we don’t use a header file. Each of these source files compiles without error, and the program links fine: because f() has external linkage, main() can call it from a different file. However, suppose you apply static to the f() prototype in AnotherFile.cpp. Note that you don’t need to repeat the static keyword in front of the definition of f(). As long as it precedes the first instance of the function name, there is no need to repeat it #include using namespace std; static void f(); void f() { cout << "f\n"; } Code snippet from Static\AnotherFile.cpp Now each of the source files compiles without error, but the linker step fails because f() has internal (static) linkage, making it unavailable from FirstFile.cpp. Some compilers issue a warning when static methods are defined but not used in that source file (implying that they shouldn’t be static, because they’re probably used elsewhere). Now that you’ve learned all about this use of static, you will be happy to know that the C++ committee finally realized that static was too overloaded, and deprecated this particular use of the keyword. That means that it continues to be part of the standard for now, but is not guaranteed to be in the future. However, much legacy C++ code still uses static in this way. The supported alternative is to employ anonymous namespaces to achieve the same affect. Instead of marking a variable or function static, wrap it in an unnamed namespace like this: #include using namespace std; namespace { void f(); void f() { cout << "f\n"; } } Code snippet from AnonymousNamespaces\AnotherFile.cpp Entities in an anonymous namespace can be accessed anywhere following their declaration in the same source file, but cannot be accessed from other source files. These semantics are the same as those obtained with the static keyword. The extern Keyword A related keyword, extern, seems like it should be the opposite of static, specifying external linkage for the names it precedes. It can be used that way in certain cases. For example, consts and typedefs have internal linkage by default. You can use extern to give them external linkage. However, extern has some complications. When you specify a name as extern, the compiler treats it as a declaration, not a definition. For variables, this means the compiler doesn’t allocate space for the variable. You must provide a separate definition line for the variable without the extern keyword. For example: extern int x; int x = 3; Code snippet from Extern\AnotherFile.cpp Alternatively, you can initialize x in the extern line, which then serves as the declaration and definition: extern int x = 3; Code snippet from Extern\AnotherFile.cpp The extern in this file is not very useful, because x has external linkage by default anyway. The real use of extern is when you want to use x from another source file: #include using namespace std; extern int x; int main() { cout << x << endl; } Code snippet from Extern\FirstFile.cpp Here FirstFile.cpp uses an extern declaration so that