我想知道下面的C片段是否正确,其中f
的定义无法重复,f
是static
链接,这是正确的:
static int f(int);
int f(int x) { return x; }
Clang不会发出任何警告。我阅读了C11标准的第6.7.1条,但没有找到我的问题的答案。
可以想象更多的问题,例如下面的t1.c和t2.c,如果答案足够普遍适用于其中一些,那将会很好,但我只是真的很关心关于上面的第一个例子。
~ $ cat t1.c
static int f(int);
int f(int);
int f(int x) { return x; }
~ $ clang -c -std=c99 -pedantic t1.c
~ $ nm t1.o
warning: /Applications/Xcode.app/…/bin/nm: no name list
~ $ cat t2.c
int f(int);
static int f(int);
int f(int x) { return x; }
~ $ clang -c -std=c99 -pedantic t2.c
t2.c:3:12: error: static declaration of 'f' follows non-static declaration
static int f(int);
^
t2.c:1:5: note: previous declaration is here
int f(int);
^
1 error generated.
答案 0 :(得分:6)
链接规则有点混乱,功能和对象不同。简而言之,规则如下:
static
表示内部联系。extern
表示已声明的链接,如果没有声明,则表示外部。extern
和对象标识符的外部链接(在同一个翻译单元中具有定义)相同。所以,这是有效的:
static int f(int); // Linkage of f is internal.
int f(int); // Same as next line.
extern int f(int); // Linkage as declared before, thus internal.
int f(int x) { return x; }
另一方面,这是未定义的行为(参见C11(n1570)6.2.2 p7):
int f(int); // Same as if extern was given, no declaration visible,
// so linkage is external.
static int f(int); // UB, already declared with external linkage.
int f(int x) { return x; } // Would be fine if either of the above
// declarations was removed.
C11 6.2.2涵盖了大部分内容。从N1570草案:
(3)如果对象或函数的文件范围标识符的声明包含存储类说明符
static
,则标识符具有内部链接。 30)(4)对于在范围内使用存储类说明符
extern
声明的标识符,其中该标识符的先前声明是可见的 31),如果先前的声明指定了内部或外部链接,后面声明中标识符的链接与先前声明中指定的链接相同。如果没有先前声明可见,或者先前声明未指定链接,则标识符具有外部链接。(5)如果函数的标识符声明没有存储类说明符,则确定其链接与使用存储类说明符
extern
声明的完全相同。如果对象的标识符声明具有文件范围而没有存储类说明符,则其链接是外部的。30)函数声明只有在文件范围内才能包含static-class说明符static;见6.7.1。
31)如6.2.1所述,后面的声明可能会隐藏先前的声明。
答案 1 :(得分:5)
根据 C11,6.2.2,7 ,它们都是未定义的行为。
如果在翻译单元中,同时出现两个标识符 内部和外部联系,行为未定义。
一个函数也是一个标识符,默认情况下一个函数(没有像 static 这样的限定符)有外部链接。
C11,6.2.1标识符范围
1标识符可以表示对象;功能;标签或结构,联合或枚举的成员;一个 typedef名称;标签名称;一个宏名;或宏参数。该 相同的标识符可以表示不同点的不同实体 该程序。枚举的成员称为枚举 不变。宏名称和宏参数不再考虑 这里,因为在程序翻译的语义阶段之前 源文件中出现的宏名称被替换为 预处理构成其宏定义的令牌序列。