我想知道下面的 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.
最佳答案
链接的规则有点困惑,对于函数和对象来说是不同的。简而言之,规则如下:
- 第一个声明决定链接。
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) 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. 30)(4) For an identifier declared with the storage-class specifier
extern
in a scope in which a prior declaration of that identifier is visible31), 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.(5) 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.30) A function declaration can contain the storage-class specifier static only if it is at file scope; see 6.7.1.
31) As specified in 6.2.1, the later declaration might hide the prior declaration.
关于c - 声明与定义的联系依据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26257763/