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


102

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

如果有什么不同,我通常会在 .h

typedef struct s s_t;

编辑

为了清楚起见,选项是头文件中的声明和类中的定义,或者头文件中的声明和定义。两者都应该导致相同的可用性,即使是通过链接实现的,不是吗?


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


2
您是否要使用不透明或不透明的结构?

4
附带说明,带有_t的标识符是POSIX保留的,因此通常不是一个好主意。你可以做typedef struct toto toto
詹斯·古斯特

我在_t其他地方(例如lighttp,linux)使用过很多东西……而我在projident_前面加上了前缀,所以这应该不是问题吗?
亚伦Yodaiken 2011年

而且@WTP,我认为通常认为非透明效果更好,更透明C,不是(FILE示例示例如何)。因此,不透明。
亚伦Yodaiken 2011年

如果它是非透明结构,则必须放入头文件中,或者您的代码不是DRY(不要重复自己)。

Answers:


107

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

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


4
我想我更同意这个答案。这不是通过其他任何.c文件使用该结构,而是该结构是否应被视为公共(因此,可以访问)。
c00kiemon5ter 2011年

@τεκ你的意思globallocal知名度?public在结构上没有意义。默认情况下,所有结构都是公共的。
BugShotGG 2015年

3
@Geo Papas这是一个关于C的问题。public这不是C 中的关键字。如果您查看下面的Matthew Slattery的答案,您会看到当用户尝试使用a的成员时,仅在标头中使用前向声明会导致编译器错误。私有(不透明)结构。
τεκ

68

两者都应该导致相同的可用性,即使是通过链接实现的,不是吗?

不,当您考虑其他具有相同头文件的.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
$

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


3
只想知道如何创建这些代码窗口,并且仍然在其中突出显示代码...手动?这个OP似乎已经使用stackoverflow离开了:'(其他人可以告诉我....
Mahesha999,2016年

很好的例子!谢谢!
Victor Haine

谢谢你举这样的例子!dereferencing pointer to incomplete type正是我的情况!
Timur Fayzrakhmanov '16

我只想补充一点,并不是所有可公开访问的结构是不好的:你可能例如想启用API的用户填写的数据并发送过来。
亚历山大Torstling

@ Mahesha999,那里没有魔术。即使您在其中添加了垃圾,SO也会突出显示代码。请注意,它在稍后的文章中试图突出显示命令行输出。
温格·森顿

8

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

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


3

关键是,将其放在头文件中使您可以通过包含多个头文件来使用多个源文件中的结构(或任何其他定义)。

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



-4

通常,无论您将它们放在头文件还是源文件中,我都认为并没有太大的区别。但是,如果您需要从多个源文件访问结构的成员,则将结构放置在头文件中并从需要该结构的任何其他文件中包含它会更容易。


8
-1:如果您关心良好的软件工程(抽象,模块化等),那么将结构定义放在何处实际上很重要
Paul R
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.