0

I have been investigating when it is possible to mix variables declared with extern, static and no storage specifier in global scope. The results have left me quite confused.

This is what I found (each paragraph is a separate compilation unit):

/* ok */
int x;
int x;

/* ok */
int f();
int f();

/* ok */
int x;
extern int x;

/* ok */
int f();
extern int f();

/* error: static declaration follows non-static declaration */
int x;
static int x;

/* ok (no warning) */
int f();
static int f();

/* ok */
extern int x;
int x;

/* ok */
extern int f();
int f();

/* ok */
extern int x;
extern int x;

/* ok */
extern int f();
extern int f();

/* error: static declaration follows non-static declaration */
extern int x;
static int x;

/* error: static declaration follows non-static declaration */
extern int f();
static int f();

/* error: non-static declaration follows static declaration */
static int x;
int x;

/* ok (no warning) */
static int f();
int f();

/* ok */
static int x;
extern int x;

/* ok */
static int f();
extern int f();

/* ok */
static int x;
static int x;

/* ok */
static int f();
static int f();

I get the same exact results with gcc and clang but I cannot find a pattern in what works and what doesn't work.

Is there any logic here?

What does the C standards say about mixing global declarations declared with extern, static and no storage specifier?

wefwefa3
  • 3,872
  • 2
  • 29
  • 51
  • 1
    There is no such thing as _"no linkage"_ WRT global variables. The standard (6.2.2 5) Is quite clear on this: _" If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external."_ – Elias Van Ootegem Oct 17 '16 at 11:37
  • Rather than learning C through that test-driven approach maybe you should grab a good book and read about it. And if you really want to know about it in the spec, download a standard draft (it's free) and read it yourself. As of now, your question is just too broad, IMO. – cadaniluk Oct 17 '16 at 11:39
  • There is no static linkage and `static` as well as `extern` are storage class specifiers in the first place. Linkage specification is a by-product. – too honest for this site Oct 17 '16 at 12:03
  • "What does the C standards say" - Why don't you read it yourself and ask about the **specific** aspect you don't understand? We are no tutoring site. – too honest for this site Oct 17 '16 at 12:05

2 Answers2

1

If you define an identifier without the keyword static, it's published in the object file and can be accessed by other modules. So if you again define that identifier without static in another module, you'll get a conflict: two published identifiers.

If you use the keyword static, then (most of) the rest of this doesn't apply.

The problem is the difference between declaring the identifier and defining it. The first says "there's going to be an identifier X with this type". The second says "here's something that I'm going to call X of this type".

  • With functions it's easy: don't provide the body, and it's merely a declaration. Provide the body, and it's a definition too. You can use extern to make this explicit in a header file but since it's the default, that's not usual.

  • With variables it's harder. Simply declaring the variable defines it too - thus you can initialise it while defining it. If you want to only declare it, you need to use the keyword extern - but then you can't initialise it too. You're saying "there's going to be a variable called X" - so you can't have the temerity of deciding its definition too!

That's why in header files all variables should be explicitly declared either extern or static:

  • The first is usual: there will be a common variable that everyone can access. Don't forget that somewhere, in one module, you need to provide the actual definition, without the extern keyword, with an optional initialisation value.
  • The second is rare: each module that includes the header file will have its own, non-conflicting variable with that particular name. The compiler may be able to not allocate memory for it (especially if it's a constant) - but if it does allocate memory, it'll be different in every module. Why would you do this? Maybe the (forced) inline functions of that header file need each module to have their own copy...
John Burger
  • 3,662
  • 1
  • 13
  • 23
0

First of all, there's nothing called "global" in standard C, it's an often misused term which can mean several different things.

If you declare something at file scope (what you call "global") and don't specify a storage class, then it defaults to external linkage. You can't declare something with no linkage at file scope. This is specified by C11 6.2.2.

Variables (emphasis mine):

If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

Functions:

If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

Lundin
  • 195,001
  • 40
  • 254
  • 396