ChatGPT解决这个技术问题 Extra ChatGPT

结构定义应该放在 .h 还是 .c 文件中?

我在标头和声明中都看到了 struct 的完整定义——一种方法比另一种方法有什么优势吗?

如果它有所作为,我通常会在 .h

typedef struct s s_t;

需要明确的是,选项是头文件中的声明和类中的定义,或者头文件中的声明和定义。两者都应该产生相同的可用性,即使一个是通过链接,不是吗?

我看到许多几乎重复的内容,例如 here 但没有完全匹配。如果我在这方面错了,请纠正我。

你想要一个不透明或不透明的结构吗?
旁注,带有 _t 的标识符由 POSIX 保留,所以这通常是一个坏主意。你可以做typedef struct toto toto
我已经看到很多 _t 使用其他地方(例如 lighttp、linux)...我用 projident_ 作为前缀,所以这应该不是问题吗?
而@WTP,我认为不透明通常被认为更好,更C,不(FILE 示例等)。所以,不透明。
如果它是一个非透明结构,它必须放在头文件中,或者你的代码不是 DRY(不要重复自己)。

τ
τεκ

该文件的私有结构应该放在 .c 文件中,如果它们被 .h 中的任何函数使用,则在 .h 文件中声明。

公共结构应该放在 .h 文件中。


我想我更同意这个答案。这与是否通过任何其他 .c 文件使用该结构无关,而是该结构是否应被视为公共(因此,可访问)。
@τεκ 你的意思是 globallocal 可见性吗? public 在结构中没有意义。默认情况下,所有结构都是公共的。
@Geo Papas 这是关于 C 的问题。public 不是 C 中的关键字。如果您查看下面 Matthew Slattery 的回答,您会看到当用户尝试使用时,仅在标头中使用前向声明会导致编译器错误私有(不透明)结构的成员。
M
Matthew Slattery

两者都应该产生相同的可用性,即使一个是通过链接,不是吗?

不,当您考虑包含相同标头的其他 .c 文件时不会。如果结构的定义对编译器不可见,则无法使用该定义的详细信息。如果有任何东西试图查看 struct s 内部,则没有定义的声明(例如,只有 struct s;)会导致编译器失败,同时仍然允许它编译 struct s *foo;(只要以后不取消引用 foo)。

比较 api.hapi.c 的这些版本:

Definition in header:                 Definition in implementation:
+---------------------------------+   +---------------------------------+
| struct s {                      |   | struct s;                       |
|     int internal;               |   |                                 |
|     int other_stuff;            |   | extern void                     |
| };                              |   | api_func(struct s *foo, int x); |
|                                 |   +---------------------------------+
| extern void                     |   +---------------------------------+
| api_func(struct s *foo, int x); |   | #include "api.h"                |
+---------------------------------+   |                                 |
+---------------------------------+   | struct s {                      |
| #include "api.h"                |   |     int internal;               |
|                                 |   |     int other_stuff;            |
| void                            |   | };                              |
| api_func(struct s *foo, int x)  |   |                                 |
| {                               |   | void                            |
|     foo->internal = x;          |   | api_func(struct s *foo, int x)  |
| }                               |   | {                               |
+---------------------------------+   |     foo->internal = x;          |
                                      | }                               |
                                      +---------------------------------+

该 API 客户端适用于任一版本:

#include "api.h"

void good(struct s *foo)
{
    api_func(foo, 123);
}

这个在实现细节中四处寻找:

#include "api.h"

void bad(struct s *foo)
{
    foo->internal = 123;
}

这将适用于“头文件中的定义”版本,但不适用于“实现中的定义”版本,因为在后一种情况下,编译器无法看到结构的布局:

$ gcc -Wall -c bad.c
bad.c: In function 'bad':
bad.c:5: error: dereferencing pointer to incomplete type
$

因此,“实现中的定义”版本可以防止意外或故意滥用私有实现细节。


只是想知道您是如何创建这些代码窗口的,并且仍然在其中突出显示代码......手动?这个 OP 似乎已经离开使用 stackoverflow :'( 其他人可以告诉我....
很好的例子!谢谢!
谢谢你的例子! dereferencing pointer to incomplete type 正是我的情况!
我想补充一点,并非所有可公开访问的结构都是不好的:例如,您可能希望让 API 的用户填写数据并将其发送。
@ Mahesha999,那里没有魔法。即使您将垃圾放入其中,SO 也会突出显示代码。请注意,它试图在帖子后面突出显示命令行输出。
n
nos

如果该结构要被其他编译单元(.c 文件)使用,请将其放在头文件中,以便您可以在任何需要的地方包含该头文件。

如果该结构仅在一个编译单元(.c 文件)中使用,则将其放在该 .c 文件中。


J
Jonathan Wood

关键是,将它放在头文件中允许您使用来自多个源文件的结构(或任何其他定义),只需包含该头文件即可。

但是,如果您确定它只会从一个源文件中使用,那么它真的没有任何区别。


T
TofuBeer

我将它们放入 C 文件中以使其更加面向对象,see this article