我一直在调查何时可以混合使用extern
,static
声明的变量以及全局范围内没有存储说明符的变量。结果让我很困惑。
这是我发现的(每个段落都是一个单独的编译单元):
/* 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();
我与gcc
和clang
获得了完全相同的结果,但我无法找到有效的模式和无效的模式。
这里有逻辑吗?
C标准对于将extern
,static
和没有存储说明符声明的全局声明混合起来有什么作用?
答案 0 :(得分:1)
如果您在没有关键字static
的情况下定义标识符,则它将在对象文件中发布,并可由其他模块访问。因此,如果您在另一个模块中再次定义没有static
的标识符,则会产生冲突:两个已发布的标识符。
如果您使用关键字
static
,那么(大部分)其余部分都不适用。
问题是声明标识符与定义之间的区别。第一个说“将会有一个这种类型的标识符X
”。第二个说“这是我要打电话给X
这种类型的东西”。
使用函数很容易:不提供正文,它只是一个声明。提供正文,它也是定义。您可以使用extern
在头文件中明确显示此内容,但由于这是默认设置,因此不常见。
使用变量会更难。只需声明变量定义它 - 因此您可以在定义时初始化它。如果您只想 声明,则需要使用关键字extern
- 但是您也无法初始化它。你说“会有一个名为X
的变量” - 所以你也不能冒然决定它的定义!
这就是为什么在头文件中所有变量应该明确地声明为extern
或static
:
extern
关键字,并提供可选的初始值。答案 1 :(得分:0)
首先,在标准C中没有任何称为“全局”的东西,它是一个经常被滥用的术语,可能意味着几种不同的东西。
如果在文件范围(您称之为“全局”)中声明某些内容并且未指定存储类,则默认为外部链接。您无法在文件范围内声明没有链接的内容。这由C11 6.2.2规定。
变量(强调我的):
如果声明对象的文件范围标识符或 function包含存储类说明符static,标识符 有内部联系。
对于使用存储类说明符extern声明的标识符 如果是,则可以看到该标识符的先前声明的范围 事先声明指定内部或外部联系, 后面声明中标识符的链接与 在先前声明中指定的联系。 如果没有事先声明 可见,或者如果先前的声明指定没有链接,那么 标识符有外部链接。
功能:
如果函数标识符的声明没有 存储类说明符,其链接确定就像它一样 用存储类说明符extern声明。如果 对象标识符的声明具有文件范围而没有 存储类说明符,其链接是外部的。