为什么结构定义有内部联系?

(我在谈论C,但它也适用于C ++中的类模板)

在头文件中,放置所有DECLARATIONS而不是定义是自定义的。 但是,我们通常将结构定义或类模板放在头文件中,而实际上并不知道为什么我们可以。 这并没有多大意义,因为它们也是定义 – 一个定义规则。 (是的,结构定义和类模板不会导致设置任何存储,但是仍然会出现“重新定义”错误,这意味着它们是定义)。

EX)在同一文件中定义具有相同标记的多个结构会给出重新定义错误,但在多个源文件中定义具有相同标记的多个结构不会导致任何错误(类同样发生)。

唯一有意义的是结构定义和类模板具有内部链接(与默认外部链接相对),但我在K&R或参考手册中找不到任何关于它的引用。 实际上,连接中甚至没有提到结构。

我想知道ANSI标准指出这种现象的确切参考。 (国际海事组织,这是一个非常模棱两可的问题,在ANSI标准的某处提到)。


编辑我不是问为什么结构定义可以放入头文件。

我问为什么在头文件中放置结构定义不会像我们在头文件中放入变量定义时那样导致重定义错误(并将其包含在多个源文件中)

EX)test1.c:int a = 3; test2.c:int a = 4; 由于重新定义导致编译错误。 然而,

test1.c:struct test {int a}; test2.c:struct test {int b}; 不会导致编译错误,我能想出的唯一原因是结构定义要么具有内部链接,要么根本没有链接。

在C中,只有对象和函数具有链接。 由于C中的struct可能不包含C ++中的函数或“ static ”成员对象,因此这里的问题没有多大意义。

C ++中的成员函数只要它们没有定义但只在struct声明就没有问题。 如果它们也被定义,则它们是inlineinline的概念刚刚为C ++发明,用于捕获这种情况:一个函数定义 ,可以通过几个编译单元中的头文件共享。 采用该概念的C99(略微修改)。

static成员对象确实更成问题。 关于如何实例化这些人的语法非常模糊,特别是对于template classstruct 。 如果你想知道那个,你必须要求它,用C ++专门标记。

结构线仅仅是一个定义。 该定义在源文件之外不可见。
仅供参考:两个源文件都没有输出任何内容。

为了测试这个:

 $ cat test1.c struct test { char a; }; $ gcc -o test1.o -c test1.c $ nm $ echo "struct test foo; " >> test1.c $ gcc -o test1.o -c test1.c $ nm 0000000000000001 C _foo 

我想你在这里混淆了一下,你可以把任何你喜欢的东西放在头文件中。

通常放在它们中的是枚举,typedef,结构和函数原型的声明,因此各种C文件可以编译而无需了解实际函数或实际内存(结构基本上是如何布局内存的定义)

结构在头文件中定义,因为头文件提供模块的接口。 在接口中定义结构时,接口的用户可以:

  • 指的是结构的成员
  • 知道结构有多大 – 否则他们无法为结构分配内存

链接与它无关 – 只有函数是链接的,而不是数据结构。

请注意,您仍然可以在头文件中声明结构,如果要隐藏结构的内部(不透明数据结构),这很有用。 接口的用户可以指向结构并将它们用作cookie的类型,但是他们不能自己分配这样的结构,或者在其中“看到”。

至于在头文件中定义结构时没有得到重定义错误,这只是因为标题保护 – 标题通常如下所示:

 #ifdef MYHEADER_H #define MYHEADER_H struct a { int x; } void f(void); /* and so on */ #endif 

因此,当包含头文件时,它通常只包含一次,因此每个转换文件只定义一次结构。 链接器与结构定义无关,因为它们没有链接。

我没有最终版本的副本,但是从规范的n843草案我看到:

6.7.2.3标签 :“4结构,联合或枚举类型的两个声明在不同的范围或使用不同的标签声明不同的类型。结构,联合或枚举类型的每个声明,不包括标签声明一个不同的类型。“

6.2.1标识符的范围 :“4每个其他标识符的范围由其声明的位置(在声明者或类型指定者中)确定。如果声明标识符的声明者或类型指定者出现在任何块或参数列表之外,标识符有文件范围 ,它终止于翻译单元的末尾。[…] [强调原文](我在本声明之前在本节中提到的唯一标识符类型是标签,它具有function范围。)

我不是C或标准的专家,但在我看来,这就解释了你所看到的行为。 因此,如果文件范围相同且结构具有重复标记,则结构应该具有冲突,因为需要具有不同标记以使它们成为不同类型。 但是如果它们处于不同的文件范围内,则没有问题,因为只要它们处于不同的范围内,就可以满足作为不同类型的要求。