31

I am beginning to question the usefulness of "extern" keyword which is used to access variables/functions in other modules(in other files). Aren't we doing the same thing when we are using #include preprocessor to import a header file with variables/functions prototypes or function/variables definitions?

Stephen
  • 1,607
  • 2
  • 18
  • 40
Midnight Blue
  • 5,061
  • 10
  • 41
  • 46

4 Answers4

27

extern is needed because it declares that the symbol exists and is of a certain type, and does not allocate storage for it.

If you do:

int foo;

In a header file that is shared between several source files, you will get a linker error because each source would have its own copy of foo created and the linker will be unable to resolve the symbol.

Instead, if you have:

extern int foo;

In the header, it would declare a symbol that is defined elsewhere in each source file.

One (and only one) source file would contain

int foo;

which creates a single instance of foo for the linker to resolve.

Lucas Jones
  • 19,767
  • 8
  • 75
  • 88
Michael
  • 54,279
  • 5
  • 125
  • 144
  • 2
    But can't you still access int foo without declaring with extern int foo as long as you include the header file containing its definition? – Midnight Blue Aug 25 '09 at 18:45
  • 2
    As jcopenha mentioned, #include just inserts the text from the included file into the source file - the compiler isn't really aware of include files and doesn't treat them specially. So if you have A.c, B.c, and C.c, each with "int foo" and you link them together, how do you resolve foo? It exists in 3 different places. extern just means, the symbol exists somewhere else. You can use it, but someone else is responsible for creating it. – Michael Aug 25 '09 at 18:54
  • You will find that for functions where there is only one instance of foo_fun() programs with modules that call foo_fun() will work with or without the extern. So in those cases you should try to be clear about it. When you get into a shared global variable you need to be really clear, some compilers figure it out, some do not. – old_timer Aug 25 '09 at 19:46
  • 1
    @Midnight Blue: I think you're confusing a coding convention with the behavior required by the C specification. It's common practice to put `extern` declarations in the header file for a code module and `#include` the header to get those declarations instead of declaring them yourself. It's the `extern` in the header that you `#include` that provides access to the variable, not the `#include` itself. – Michael Carman Aug 25 '09 at 20:15
  • I've seen declarations that go like `Type array[];` in headers. But there is a subtle difference of that to `extern Type array[];`! The former is a *tentative definition*, which will be treated like `Type array[1];` when there is no definition including the size until the end of the translation unit. But if you put `extern` before it, you just say "The size is given elsewhere", and that's what is most often wanted. – Johannes Schaub - litb Aug 29 '09 at 16:45
3

No. The #include is a preprocessor command that says "put all of the text from this other file right here". So, all of the functions and variables in the included file are defined in the current file.

jcopenha
  • 3,935
  • 1
  • 17
  • 15
2

The #include preprocessor directive simply copy/pastes the text of the included file into the current position in the current file.

extern marks that a variable or function exists externally to this source file. This is done by the originator ("I am making this data available externally"), and by the recipient ("I am marking that there is external data I need"). A recipient with an unsatisfied extern will cause an Undefined Symbol error.

Which to use? I prefer using #include with the include guard pattern:

#ifndef HEADER_NAME_H
#define HEADER_NAME_H
<write your header code here>
#endif

This pattern allows you to cleanly separate anything you want an outsider to have access to into the header, without worrying about a double-include error. Any time I have to open a .c file to find what externs are available, the lack of a clear interface makes my soul gem crack.

64BitLich
  • 21
  • 4
2

There are indeed two ways of using functions/variables across translation units (a translation unit is usually a *.c/*.cc file).

One is the forward declaration:

  • Declare functions/variables using extern in the calling file. extern is actually optional for functions (functions are automatically extern), but not for variables.
  • Implement the function/variables in the implementing file.

The other is using header files:

  • Declare functions/variables using extern in a header file (*.h/*.hh). Still, extern is optional for functions, but not for variables. So you don't normally see extern before functions in header files.
  • In the calling *.c/*.cc file, #include the header, and call the function/variable as needed.
  • In the implementing *.c/*.cc file, #include the header, and implement the function/variable.

Google C++ style guide has some good discussions on the pros and cons of the two approaches.

Personally, I would prefer the header file approach, as it is the single place (the header file) a function signature is defined, calling and implementation all adhere to this one piece of definition. Thus, there would be no unnecessary discrepancies that might occur in the forward declaration approach.

Zine.Chant
  • 63
  • 6