Mixing declarations with extern, static and no storage specifier in global scope

天大地大妈咪最大 提交于 2019-12-08 13:59:43

问题


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?


回答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...



回答2:


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.



来源:https://stackoverflow.com/questions/40085329/mixing-declarations-with-extern-static-and-no-storage-specifier-in-global-scope

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!