C++ 范围中的结构与函数定义

C++ 范围中的结构与函数定义,c++,c,linkage,C++,C,Linkage,据我所知,这在C中是合法的: foo.c struct foo { int a; }; struct foo { char a; }; int foo() { return 1; } int foo() { return 0; } bar.c struct foo { int a; }; struct foo { char a; }; int foo() { return 1; } int foo() { return 0

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

foo.c

struct foo {
   int a;
};
struct foo {
    char a;
};
int foo() {
    return 1;
}
int foo() {
    return 0;
}
bar.c

struct foo {
   int a;
};
struct foo {
    char a;
};
int foo() {
    return 1;
}
int foo() {
    return 0;
}
但同样的事情对于函数也是非法的:

foo.c

struct foo {
   int a;
};
struct foo {
    char a;
};
int foo() {
    return 1;
}
int foo() {
    return 0;
}
bar.c

struct foo {
   int a;
};
struct foo {
    char a;
};
int foo() {
    return 1;
}
int foo() {
    return 0;
}
并将导致链接错误(函数的多个定义
foo

为什么呢?结构名和函数名之间有什么区别使得C不能处理其中一个而不能处理另一个? 这种行为是否也扩展到C++?< /p> 为什么呢

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

<>请注意,C和C++如何处理不兼容的<代码>结构> <代码>定义。 在您发布的代码中,
struct foo
的不同定义在C程序中是可以的,只要您不混合使用它们


<>但是,C++中不合法。在C++中,它们具有外部链接,必须定义相同。有关更多详细信息,请参阅。

与其说名称不同,不如说存在差异;结构定义不存储在任何位置,其名称仅在编译期间存在。
(程序员有责任确保在使用同名结构时不存在冲突。否则,我们亲爱的老朋友Undefined Behavior会打电话来。)

另一方面,函数需要存储在某个地方,如果它有外部链接,则链接器需要它的名称


如果将函数设置为静态,使其在各自的编译单元外“不可见”,则链接错误将消失。

函数定义都声明了一个名为
foo
的实体,该实体具有外部链接,C标准规定,对于具有外部链接的实体,不能有一个以上的定义。您定义的结构类型不是具有外部链接的实体,因此可以有多个
struct foo
定义

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

富科

酒吧c

现在有两个名为
obj
的对象,它们都具有外部链接,这是不允许的

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

富科

酒吧c

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


C++有类似但更复杂的规则,用于解释<代码>内联< /COD>函数和<代码>内联< /COD>变量、模板和其他C++特性。在C++中,相关的要求被称为一个定义规则(ODR)。一个显著的区别是,C++甚至不允许两个不同的代码<结构> /COD>定义,即使它们从不用于声明具有外部链接的对象,也不被用于“共享”。翻译单元之间。

struct foo的两个声明互不兼容,因为成员的类型不同。在每个翻译单元中都使用这两种语言是可以的,只要您不做任何事情来混淆这两种语言

例如,如果您这样做:

foo.c:

struct foo {
   char a;
};

void bar_func(struct foo *f);

void foo_func()
{
    struct foo f;
    bar_func(&f);
}
B.c:

struct foo {
   int a;
};

void bar_func(struct foo *f)
{
    f.a = 1000;
}
您将进行调用,因为
bar_func
期望的
struct foo
foo_func
提供的
struct foo
不兼容

结构的兼容性详见本手册第6.2.7节:

1如果两种类型相同,则它们具有兼容类型。确定两种类型是否兼容的其他规则包括 6.7.2中描述了类型说明符,6.7.3中描述了类型限定符, 在6.7.6中,对于声明者。此外,两个结构、联合或 在单独的转换单元中声明的枚举类型是兼容的 其标签和成员是否满足以下要求:如果 使用标签声明的,另一个应使用相同的标签声明。 如果两者都在各自翻译范围内的任何地方完成 单位,则以下附加要求适用:应 成员之间的一对一通信,以便 使用兼容类型声明一对对应的成员;如果 使用对齐说明符声明对中的一个成员,即 另一个是使用等效的对齐说明符声明的;如果有 对中的一个成员用名称声明,另一个成员用名称声明 同名。对于两个结构,应使用相应的构件 以相同的顺序声明。对于两个结构或联合体, 相应的位字段应具有相同的宽度。两个人 枚举时,相应的成员应具有相同的值

2所有引用相同对象或函数的声明应具有兼容类型;否则,行为是未定义的

总之,
struct foo
的两个实例必须具有相同名称和类型且顺序相同的成员才能兼容


需要这样的规则,以便可以在头文件中定义一次
struct
,并且该头随后包含在多个源文件中。这将导致在多个源文件中定义
结构,但每个实例都是兼容的。

要对链接器隐藏函数定义,请使用关键字static

富科

酒吧c


在这种情况下,区别概念称为链接

在C结构中,union或enum标记没有链接。它们实际上是其范围的局部

6.2.2标识符的链接
6以下标识符没有链接:已声明的标识符