范围中的结构与函数定义

V0l*_*dek 28 c c++ linkage

所以,据我所知,这在C中是合法的:

foo.c的

struct foo {
   int a;
};
Run Code Online (Sandbox Code Playgroud)

bar.c

struct foo {
    char a;
};
Run Code Online (Sandbox Code Playgroud)

但功能相同是非法的:

foo.c的

int foo() {
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

bar.c

int foo() {
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

并将导致链接错误(函数的多重定义foo).

这是为什么?结构名称和函数名称之间的区别是什么使C无法处理一个而不能处理另一个?这种行为也扩展到C++吗?

R S*_*ahu 24

这是为什么?

struct foo {
   int a;
};
Run Code Online (Sandbox Code Playgroud)

定义用于创建对象的模板.它不会创建任何对象或功能.除非struct foo在代码中的某处使用,否则就编译器/链接器而言,这些代码行也可能不存在.

请注意,C和C++处理不兼容struct定义的方式有所不同.

struct foo您发布的代码中的不同定义在C程序中是可以的,只要您不混用它们的用法即可.

但是,它在C++中是不合法的.在C++中,它们具有外部链接,必须以相同的方式定义.有关详细信息,请参见3.2一个定义规则/ 5.

  • @ V0ldek,是的,这是正确的.如果你不混合它们,即不将foo.c中的`foo`传递给期望来自bar.c的`foo`的函数,你应该没问题. (2认同)
  • 在C++中,它违反了ODR (2认同)

AnT*_*AnT 18

在这种情况下,区别概念称为联系.

在C struct中,union或enum标记没有链接.它们的范围实际上是本地的.

6.2.2标识符的链接
6以下标识符没有链接:声明为对象或函数以外的任何标识符; 声明为函数参数的标识符; 没有存储类说明符声明的对象的块作用域标识符extern.

它们不能在同一范围内重新声明(除了所谓的前向声明).但它们可以在不同的范围内自由重新声明,包括不同的翻译单元.在不同的范围内,他们可以声明完全独立的类型.这就是您的示例中的内容:在两个不同的翻译单元(即两个不同的文件范围)中,您声明了两种不同且不相关的struct foo类型.这是完全合法的.

同时,函数在C中具有链接.在您的示例中,这两个定义foo使用外部链接定义相同的函数.并且不允许在整个程序中提供任何外部链接功能的多个定义

6.9外部定义
5 [...]如果在表达式中使用了使用外部链接声明的标识符(除了作为结果为整数常量的运算符sizeof_Alignof操作符的操作数的一部分),整个程序中的某个地方应该准确标识符的一个外部定义; 否则,不得超过一个.


在C++中,链接的概念得到了扩展:它为更广泛的实体(包括类型)分配特定的链接.在C++类类中有链接.在命名空间范围内声明的类具有外部链接.C++的一个定义规则明确指出,如果具有外部链接的类具有多个定义(跨不同的翻译单元),则应在所有这些翻译单元中等效地定义(http://eel.is/c++draft/basic .def.odr#12).因此,在C++中,您的struct定义将是非法的.

由于C++ ODR规则,您的函数定义在C++中仍然是非法的(但基本上与C中的原因相同).


Jon*_*ely 12

您的函数定义都声明了一个foo使用外部链接调用的实体,而C标准表示不能有多个具有外部链接的实体的定义.您定义的结构类型不是具有外部链接的实体,因此您可以拥有多个定义struct foo.

如果使用相同的名称声明具有外部链接的对象,那么这将是一个错误:

foo.c的

struct foo {
   int a;
};
struct foo obj;
Run Code Online (Sandbox Code Playgroud)

bar.c

struct foo {
    char a;
};
struct foo obj;
Run Code Online (Sandbox Code Playgroud)

现在你有两个被称为obj外部链接的对象,这是不允许的.

即使其中一个对象仅被声明而未定义,它仍然是错误的:

foo.c的

struct foo {
   int a;
};
struct foo obj;
Run Code Online (Sandbox Code Playgroud)

bar.c

struct foo {
    char a;
};
extern struct foo obj;
Run Code Online (Sandbox Code Playgroud)

这是未定义的,因为两个声明obj引用相同的对象,但它们没有兼容的类型(因为struct foo在每个文件中定义不同).

C++具有类似但更复杂的规则,以考虑inline函数和inline变量,模板和其他C++特性.在C++中,相关要求称为单一定义规则(或ODR).一个值得注意的区别是C++甚至不允许这两个不同的struct定义,即使它们从未用于声明具有外部链接的对象或在翻译单元之间"共享".