1

In the program

case0.c

int main()
{
    int x;
    x = 4;
}

x is first declared as an int, and memory is allocated for x on the following line. No problems here.

However, if I write the files (as part of a bigger program)

case1.c

extern int x; 
x = 4; 

I get, from gcc, warning: data definition has no type or storage class. Similarly, if I do

case2.c

extern int x = 4;

gcc also doesn't like it and gives warning: 'x' initialized and declared 'extern'

The only case that doesn't throw any warnings is

case3.c

extern int x;
int x = 4;

Why does case 1 give an error, when case 0 doesn't? Is case 3 the one and only way I should define external variables?

user56202
  • 299
  • 1
  • 9
  • Can you make these examples more complete? In particular, are your code examples written inside a function, or at top level? – Nate Eldredge Apr 13 '22 at 18:00
  • 1
    One note is to be careful and precise about distinguishing the concept of *defining* a variable from the concept of *declaring* it. – Nate Eldredge Apr 13 '22 at 18:01
  • 1
    You say "x is first declared as an int, and memory is allocated for x on the following line". That's a complete misinterpretation of what happens. The memory is allocated by the `int x;` line, leaving an uninitalized local variable. The assignment on the next line uses the previously allocated storage. The two lines should be replaced by `int x = 4;` to initialize (rather than assign to) the variable. – Jonathan Leffler Apr 13 '22 at 18:01
  • @NateEldredge Yes, I will update them. Cases 1 - 3 are at the top level. – user56202 Apr 13 '22 at 18:02
  • Is your goal to *declare* a variable with external linkage, whose definition is in another source file, so that you can access it in this file? Or to *define* such a variable so that other source files could access it? – Nate Eldredge Apr 13 '22 at 18:03
  • Okay, then for starters, `x=4;` by itself is completely invalid at top level. It's an assignment statement, i.e. "executable code", which makes no sense outside a function. – Nate Eldredge Apr 13 '22 at 18:03
  • I'm sure there's a duplicate question elsewhere on the site, but the short answer is that exactly one source file in your program should have `int x = 4;` (the definition) at top level. Note the definition does not include the `extern` keyword. All others should have the declaration `extern int x;`, either at top level or in whatever scope needs to access the variable. Preferably included from an appropriate header file to avoid code duplication. – Nate Eldredge Apr 13 '22 at 18:05
  • AFAICR, in the olden days, when "implicit `int`" was a thing (meaning in the last millennium, before C99), then writing `x = 4;` at file scope was equivalent to `int x = 4;`. It hasn't been valid in the current C standard for the whole of this millennium — so anyone learning C now should forget about "implicit `int`" unless they are dealing with antiquated code. If you are handling antiquated code, aim to fix "implicit `int`" issues, and all the other antiquated misused features (lack of function prototypes, using functions without a declaration in scope, and so on). – Jonathan Leffler Apr 13 '22 at 18:05
  • See [How do I use `extern` to share variables between source files?](https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files/1433387#1433387) for a lot of discussion about using `extern`. – Jonathan Leffler Apr 13 '22 at 18:06
  • @NateEldredge Ahhh thank you. The confusion came from me thinking that the source file which defines x must contain the `extern` keyword as well, to make this variable "visible" to other source files. – user56202 Apr 13 '22 at 18:16
  • @NateEldredge `...either at top level or in whatever scope needs to access the variable. Preferably included from an appropriate header file to avoid code duplication.` If you want to provide the variable to some limited scope (say, in just one function), you would have to `#include` a header in that function. I thought it is bad practice to do this. Is this not so? – user56202 Apr 13 '22 at 18:19
  • @JonathanLeffler Thank you for pointing out my misunderstanding. – user56202 Apr 13 '22 at 18:20
  • @user56202: Yeah, the header would normally be for when you wanted to declare it at top level. Declaring it inside a function is not usual practice and would tend to only be done in special circumstances. But those special circumstances might also justify using `#include` in unusual ways. – Nate Eldredge Apr 14 '22 at 05:22

2 Answers2

1

x is first declared as an int, and memory is allocated for x on the following line. No problems here.

No, that is not what happens. Inside a function, int x; defines x, which reserves memory for it. Then x = 4; stores a value in that memory.

extern int x;
x = 4;

extern int x; declares there to be an x but does not define it. If the program uses this x, it should define it somewhere else.

Outside a function, only declarations should appear. However, x = 4; is a statement, so it is not proper outside a function.

extern int x = 4;

This is valid C, but it is unconventional usage, so the compiler warns you. Conventionally, we write int x = 4; to define and initialize x, and we write extern int x; to declare x without defining it.

extern int x = 4; is defined by the standard; in this context, it is effectively the same as int x = 4;. But programmers generally do not use that form.

(If there is a visible prior declaration of x, such as static int x;, then extern int x = 4; does differ from int x = 4;. extern int x = 4; will refer to the x of the prior declaration, whereas int x = 4; will attempt to create a new x.)

extern int x;
int x = 4;

extern int x; declares x but does not define it.

int x = 4; defines x and initializes it.

Is case 3 the one and only way I should define external variables?

If you only need to use x in one translation unit, you can use int x = 4; by itself, without extern int x;. If you need to use x in multiple translation units, you should put extern int x; in a header file and include that header file in each source file that uses x, including the one that defines it.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
1

"Is case 3 the one and only way I should define external variables?"

No, not if it is to be visible and usable by other source files in the project. If it is only to be used in the file in which it is created, there is no reason to give it extern duration.

The scenario requiring a variable with extern duration is when the value it stores is required to be referenced by multiple source files.

A common way (place) to create extern variables to support that scenario :

  • Declare variable with extern modifier in a header file.
  • Define the extern variable in a project file with visibility to its declaration. (eg, can be either a .h or .c . More commonly done in .c) If defined in a file other than the declaration file, file must #include the declaration file.
  • Use the extern variable in any source file by # including its declaration file

Example:

file.h

//anywhere in header file
extern int g_number;//declare extern variable.  
                    //Note extern keywork required only during declaration
                    //Not during definition

//prototypes
void output_extern_variable( void );
void update_extern_variable( void );    
...

file.c

//in file global space
#include "file.h" 

int g_number = 25;//define extern variable
int main(void)
{
    output_extern_variable();
    update_extern_variable(); 
    output_extern_variable();

...

file2.c

#include "file.h"
...

void output_extern_variable(void)
{
    printf("Value of g_number is: %d\n", g_number);
}

void update_extern_variable( int *var )
(
    g_number += 1;
)
ryyker
  • 22,849
  • 3
  • 43
  • 87