在 C11 中链接翻译单元的规则是什么?

What are the rules for linking translation units in C11?

C11 标准讨论了标识符的 link 时代,但没有明显讨论 linking 翻译单元的规则。我的问题是通过使用 clang 编译两个简单示例提出的。

这是我的第一个示例,它有两个相同函数但类型不兼容的声明:

//testall.c
extern char myfun(void*);

int main(){
  char a='c';
  a=myfun(&a);
}

char myfun(char*c){
  return *c;
}

然后我运行 命令:$clang -std=c11 testall.c
然后clang报错:

testall.c:9:10: error: conflicting types for 'myfun'
char myfun(char*c){
</code> <code> ^
testall.c:2:17: note: previous declaration is here
extern char myfun(void*);
</code> <code> </code> <code> </code> <code> </code> <code> ^
1 error generated.

我理解这个错误,因为 void 指针和指向 char 的指针是不兼容的类型。
令我困惑的是,当我将两个声明分成两个不同的翻译单元,然后 link 将它们合二为一时,clang 没有报告任何错误:

//test.c
extern char myfun(void*);

int main(){
  char a='c';
  a=myfun(&a);
}

// mylib.c
char myfun(char*c){
  return *c;
}

然后我运行这个命令:$clang -std=c11 test.c mylib.c.
clang 编译并 links 这两个翻译单元,而不会报告任何错误或警告。

我在想 linking 两个翻译单元遵循 C11 标准第 6.2.2 节标识符链接中的规则。但似乎并非如此。谁能帮我澄清一下?

这只是未定义的行为。 C11 没有说明 linkers 或它们如何组合多个翻译单元。实际上,这不是问题,因为会有一个包含 myfun() 函数声明的头文件,其中包含这两个 C 文件。

在包含两个单独文件的示例中,行为未定义。这是我的“案例”,基于 C11 标准:

C11 6.2.2(4):

For an identifier declared with the storage-class specifier extern ... If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

test.c中,myfun有外部链接,因为它是用extern声明的,没有可见的先前声明。

C11 6.2.2(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.

mylib.c中,myfun声明时没有storage-class说明符,因此就好像它是用extern声明的一样,因此它在此具有外部链接还有翻译单元。

C11 6.9.1.(7) [函数定义]:

If the declarator includes a parameter type list, the list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit

因此 mylib.cmyfun 的定义也是 myfun 的声明(如果您有任何疑问)。

C11 6.2.2(2):

In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function.

因此两个 myfun 表示相同的功能。

C11 6.2.7(2):

All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

myfun 的两个声明具有不兼容的类型(我可以显示 如果你愿意的话,但这就是 Clang 在 single-file 中抱怨的原因 case.) 因此整个程序的行为是未定义的。

请注意 6.2.7(2) 不是 约束,因此 Clang 不是 需要在违反时发出诊断。然而, 在单个文件的情况下,存在实际的约束违规, 因为标题 "Constraints" 下出现以下内容:

C11 6.7(4):

All declarations in the same scope that refer to the same object or function shall specify compatible types.

所以 Clang 必须在这种情况下发出诊断。