3

(我说的是 C,但它也适用于 C++ 中的类模板)

在头文件中,习惯于放置所有声明,而不是定义。但是,我们通常也将结构定义或类模板放在头文件中,而实际上并不知道为什么可以这样做。这实际上没有任何意义,因为它们也是定义——一个定义规则。(是的,结构定义和类模板不会导致设置任何存储,但您仍然会在下面看到“重新定义”错误,这意味着它们是定义)。

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

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

我想知道 ANSI 标准指出这种现象的确切参考。(IMO,这是一个非常模糊的事情,必须在 ANSI 标准中的某个地方提到)。


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

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

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

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

4

5 回答 5

4

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

C++ 中的成员函数,只要它们没有被定义,而只是在struct姿势内部声明就没有问题。如果它们也被定义,它们是inline. inline刚刚为 C++ 发明的概念是为了捕捉这种情况:可以通过多个编译单元中的头文件共享的函数定义。采用该概念的 C99(稍作修改)。

static成员对象确实带来了更多的问题。如何实例化这些家伙的语法非常晦涩,尤其是对于template classes 或structs。如果你想知道那个,你必须问那个,用 C++ 专门标记。

于 2011-08-14T21:44:44.597 回答
2

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

  • 引用结构的成员
  • 知道结构有多大 - 否则他们无法为结构分配内存

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

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

至于在头文件中定义结构时不会出现重新定义错误,这仅仅是因为头文件保护 - 头文件通常如下所示:

#ifdef MYHEADER_H
#define MYHEADER_H

struct a { int x; }
void f(void);
/* and so on */

#endif

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

于 2011-08-14T21:28:32.740 回答
1

struct 行只是一个定义。该定义在源文件之外不可见。
仅供参考:源文件都没有导出任何内容。

要对此进行测试:

$ 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
于 2011-08-14T21:56:14.707 回答
0

我认为你在这里有点混淆了,你可以把你喜欢的任何东西放在头文件中。

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

于 2011-08-14T21:32:10.353 回答
0

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

来自6.7.2.3 标签:“4 在不同范围内或使用不同标签的结构、联合或枚举类型的两个声明声明不同的类型。不包含标签的结构、联合或枚举类型的每个声明都声明一个不同的类型。”

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

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

于 2011-08-14T21:54:22.087 回答