c - 声明与定义的联系依据

标签 c language-lawyer c11

我想知道下面的 C 代码片段,其中 f 的定义未能重复 fstatic 链接,是否是正确:

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/

相关文章:

C Socket 下载 .exe 大 6 倍?

c++ - 在泛型编程中使用 placement new

c++ - 类成员限定名称查找

c - 在 malloc 的结构中初始化原子标志

c - thrd_join 的返回值与其 res 参数的区别?

c - 在 C 中监视 stdin、stdout 和 stderr 中的字节

c - 结构定义中的结构指针

c - mex 文件和使用 coder.ceval 调用的函数之间有什么区别吗?

c - C对象的存储布局

c99 - 错误 : unknown type name ‘pid_t’