3

Why should I use the extern keyword in the following code:

header.h

float kFloat; // some say I should write 'extern float kFloat;', but why?

file.c

#include <stdio.h>
#include "Header.h"

float kFloat = 11.0f;

main.c

#include <stdio.h>
#include "Header.h"

int main(int argc, const char * argv[])
{
    printf("The global var is %.1f\n", kFloat);

    return 0;
}

This code works. The global Variable kFloat defaults to external linkage and static lifetime.

Output is:

The global var is 11.0

I don't understand in which case the problem would occur, can anyone give me an example where it would crash?

Binarian
  • 12,296
  • 8
  • 53
  • 84

5 Answers5

9
extern float kFloat;

declares kFloat without defining it.

but:

float kFloat;

also declares kFloat but is a tentative definition of kFloat.

Adding extern just suppresses the tentative definition. In a header file you only want declarations, not definitions.

If the tentative definition is included in several source files, you will end up having multiple definitions of the same object which is undefined behavior in C.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 1
    Ah, I read the special tentative definition rules in C, thanks for bringing that up. Here is a link with a good description: http://stackoverflow.com/questions/3095861/about-tentative-definition – Binarian Oct 05 '13 at 16:10
3

extern indicates that a variable is defined somewhere in the project (or outside function block) that you want to use. It does not allocate memory for it since you are telling the compiler that this is defined else where.

A variable must be defined once in one of the modules of the program. If there is no definition or more than one, an error is produced, possibly in the linking stage.

Definition refers to the place where the variable is created or assigned storage; declaration refers to places where the nature of the variable is stated but no storage is allocated.

And since it will be accessible elsewhere it needs to be static.

Sadique
  • 22,572
  • 7
  • 65
  • 91
3

Always put the definition of global variables(like float kFloat;) in the .c file, and put the declarations (like extern float kFloat;) in the header.

Otherwise when multiple .c files include the same header, there will be a multiple definition error.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • I can't reproduce the definition error, I don't really understand what you mean. – Binarian Oct 05 '13 at 14:44
  • @ViktorLexington The error happens when linking, not compiling, did you do the linking? – Yu Hao Oct 05 '13 at 14:48
  • I run the main.c code and the output prints without problem, so they are all linked. And the output value is 11.0. – Binarian Oct 05 '13 at 14:50
  • 1
    @ViktorLexington I see. So in your main.c, you still have `float kFloat = 11.0f;` that's **tentative definition**, see @ouah's answer, he has a better explanation on this. To reproduce the multiple definition error, you need to remove this and have only the definition in the header. – Yu Hao Oct 05 '13 at 14:55
  • But that is the point: I have no errors, why should I change the code. Of course I get errors if I change the wrong thing in the code, but where is the error, when I use this code in a bigger project? – Binarian Oct 05 '13 at 14:59
  • 1
    @ViktorLexington If I understand it correctly, tentative definition is still definition, so you will have undefined behavior if the header is included in multiple files. Undefined behavior means even if everything works fine on one machine, it may not on another. – Yu Hao Oct 05 '13 at 15:08
2

Firstly, it is strange that your code is compiling. It should throw compile time error for double definition of kFloat variable in File.c.

Secondly, if you are trying to use the common variable in two files then it should not be defined in the header.h. You should use extern keyword in header file so that the file which includes the header.h gets to know that it has been defined externally.

Now, you can define the variable globally in any of the c files and then use the variable as a common variable.

Vivek Agrawal
  • 113
  • 11
  • But the definition in the header has default external linkage, so I don't need the extern keyword to get access to the variable. I use the c11 compiler and even tried it with the c99, both without a warning. – Binarian Oct 05 '13 at 14:39
  • @ViktorLexington: the definition in the header file is tentative because it is not initialized there. Therefore it is not throwing any error because it is not conflicting any real definition. And when kFloat is initialized in file.c, it got real definition. So the same variable is visible in both main.c and file.c with same value. Now, in particular this case, there is no need of extern until you initialize the variable in header file. But I would recommend extern in header file because you would get error if no definition is provided in either of the c file. – Vivek Agrawal Oct 05 '13 at 15:04
  • 1
    For more info refer answer in the following post:http://stackoverflow.com/questions/8108634/global-variables-in-header-file?rq=1 – Vivek Agrawal Oct 05 '13 at 15:04
2

Why should I use extern ...?

Well, you shouldn't. Plain and simple. Because you shouldn't use global variables, and they are the only ones that would need the extern keyword.

Whenever you feel tempted to use a global variable, think again. At the absolute maximum, you might need to use a variable with file scope (using the static keyword), typically such a variable would be accompanied by a handful of functions that manipulate/use its value, but the variable itself should not be visible beyond the scope of the file. Usage of global variable only leads to intractably tangled code that is almost impossible to change without introducing a ton of bugs.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • Some books suggest the use of global constant variable instead of Macros because of added type information. – Binarian Oct 05 '13 at 14:54
  • 1
    Ah, yes, that would be one valid use of the `extern` keyword, because such a 'variable' would not be variable but constant. However, other books discourage the use of `const` variables because C cannot eliminate the runtime storage of such a variable as C++ does. If I don't use a `#define`, I would either use an `enum` or a `static const` variable for compile time constants, not `extern`. – cmaster - reinstate monica Oct 05 '13 at 15:16
  • There is an element of truth behind your assertions, but there is an element of over-statement too. For example, the global variables `stdin`, `stdout` and `stderr` are much more convenient than any scheme not using global variables. You could create functions to 'get' the values, I suppose, but it would not be the same world. – Jonathan Leffler Oct 07 '13 at 09:46