为什么结构定义具有内部链接?

发布于 2024-11-30 02:27:58 字数 730 浏览 1 评论 0原文

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

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

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

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

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


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

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

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

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

(I am talking about C, but it also applies to class templates in C++)

In header file, it is a custom to put all the DECLARATIONS, not definitions. However, we usually put structure definitions or class templates in header file as well without actually knowing why we can. This doesn't really make sense because they are definitions as well -- ONE DEFINITION RULE. (Yes, structure definitions and class templates don't cause any storage to set, but you still get "redefinition" error below which implies that they are definitions).

EX) defining multiple structures with same tag within same file give you a redefinition error, but defining multiple structures with same tag in multiple source files don't cause any error (same thing happens with class).

The only thing that makes sense is that structure definitions and class templates have internal linkage (opposed to default external linkage), but I can't find any references about it in K&R or reference manual.
In fact, structures are not even mentioned in linkage.

I want to know the exact reference where ANSI standard points out this pheonomenon.
(IMO, this is a pretty ambiguous thing which HAS TO be mentioned in ANSI standard somewhere).


EDIT
I am NOT asking why structure definitions can be put into the header file.

I am asking why putting structure definition in header file won't cause redefinition error like it does when we put variable definitions in header file (and include it in multiple source files)

EX)
test1.c: int a = 3;
test2.c: int a = 4;
Causes compile error because of redefinition. However,

test1.c: struct test { int a };
test2.c: struct test { int b };
Does not cause compile error, and the only reason I can come up with is that
structure definitions either have internal linkage, or no linkage at all.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

怀中猫帐中妖 2024-12-07 02:27:58

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

C++ 中的成员函数只要未定义而仅在 struct 内声明就不会出现问题。如果它们也被定义,那么它们是内联的。 内联 的概念刚刚为 C++ 发明,用于捕获这种情况:可以通过头文件在多个编译单元中共享的函数定义。 C99 采用了这个概念(稍作修改)。

static 成员对象确实带来了更多问题。如何实例化这些家伙的语法相当晦涩,尤其是对于 template classstruct 而言。如果您想了解这一点,您必须询问它,并专门用 C++ 标记。

In C only objects and functions have linkage. Since struct in C may not contain functions or "static" member objects as in C++ your question makes not much sense, here.

Member functions in C++ as long as they are not defined but only declared inside the struct pose no problem. If they are also defined, they are inline. The concept of inline was just invented for C++ to capture that case: a function definition that can be shared through a header file in several compilation units. C99 that adopted that concept (modifying it slightly).

static member objects pose indeed more of a problem. The syntax on how to instantiate these guys is quite obscure, especially for template classes or structs. If you'd like to know about that one you'd have to ask for that, tagged specifically with C++.

带刺的爱情 2024-12-07 02:27:58

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

  • 参考结构体的成员
  • 知道该结构体有多大 - 否则他们无法为该结构体分配内存

链接与此无关it - 仅链接函数,而不链接数据结构。

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

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

#ifdef MYHEADER_H
#define MYHEADER_H

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

#endif

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

Structures are defined in a header file because the header file provides the interface to a module. When the structure is defined in the interface, it is possible for the users of the interface to:

  • refer to the members of the structure
  • know how large the structure is - otherwise they couldn't allocate memory for the structure

Linkage has nothing to do with it - only functions are linked, not the data structures.

Note that you can still declare a structure in a header file, which is useful if you want to hide the internals of the structure (opaque data structure). Users of the interface can have pointers to the structure and use them as kind of a cookie, but they cannot allocate such a structure themselves, or "see" inside it.

As for not getting a redefinition error when defining a structure in a header file, that's simply because of header guards - a header typically looks like this:

#ifdef MYHEADER_H
#define MYHEADER_H

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

#endif

So when including a header file, it is usually included only once and therefore the structure is only defined once per translation file. The linker has nothing to do with the structure definitions as they have no linkage.

初与友歌 2024-12-07 02:27:58

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

要测试这一点:

$ 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

The struct line is merely a definition. The definition is not visible outside of the source file.
FYI: Neither source file exports anything.

To test this:

$ 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
你げ笑在眉眼 2024-12-07 02:27:58

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

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

I think you are mixing yourself up a bit here, you can put whatever you like in a header file.

The usual things to put in them are declarations of enums, typedefs, structs, and function prototypes so various C files can compile without having to have knowledge of the actual function or actual memory ( a struct basically is definition of how memory is laid out )

送君千里 2024-12-07 02:27:58

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

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

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

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

I don't have a copy of a final version, but from the n843 draft of the specification I see:

from 6.7.2.3 Tags: "4 Two declarations of structure, union, or enumerated types which are in different scopes or use different tags declare distinct types. Each declaration of a structure, union, or enumerated type which does not include a tag declares a distinct type."

from 6.2.1 Scopes of Identifiers: "4 Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit. [...]" [emphasis in original] (The only identifier type that I see mentioned in this section prior to this statement was labels, which have function scope.)

I'm no expert on C or the standards, but it looks to me like this explains the behavior you are seeing. So, a struct should have a collision if the file scope is the same and the struct has a duplicate tag, because having a distinct tag would be required to make them distinct types. But if they are in a different file scope, there's no problem, because as long as they are in different scopes, the requirements are met for being a distinct type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文