我在标头和声明中都看到了 struct
的完整定义——一种方法比另一种方法有什么优势吗?
如果它有所作为,我通常会在 .h
typedef struct s s_t;
需要明确的是,选项是头文件中的声明和类中的定义,或者头文件中的声明和定义。两者都应该产生相同的可用性,即使一个是通过链接,不是吗?
我看到许多几乎重复的内容,例如 here 但没有完全匹配。如果我在这方面错了,请纠正我。
_t
的标识符由 POSIX 保留,所以这通常是一个坏主意。你可以做typedef struct toto toto
。
_t
使用其他地方(例如 lighttp、linux)...我用 projident_ 作为前缀,所以这应该不是问题吗?
C
,不(FILE
示例等)。所以,不透明。
该文件的私有结构应该放在 .c 文件中,如果它们被 .h 中的任何函数使用,则在 .h 文件中声明。
公共结构应该放在 .h 文件中。
两者都应该产生相同的可用性,即使一个是通过链接,不是吗?
不,当您考虑包含相同标头的其他 .c 文件时不会。如果结构的定义对编译器不可见,则无法使用该定义的详细信息。如果有任何东西试图查看 struct s
内部,则没有定义的声明(例如,只有 struct s;
)会导致编译器失败,同时仍然允许它编译 struct s *foo;
(只要以后不取消引用 foo
)。
比较 api.h
和 api.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
$
因此,“实现中的定义”版本可以防止意外或故意滥用私有实现细节。
dereferencing pointer to incomplete type
正是我的情况!
如果该结构要被其他编译单元(.c 文件)使用,请将其放在头文件中,以便您可以在任何需要的地方包含该头文件。
如果该结构仅在一个编译单元(.c 文件)中使用,则将其放在该 .c 文件中。
关键是,将它放在头文件中允许您使用来自多个源文件的结构(或任何其他定义),只需包含该头文件即可。
但是,如果您确定它只会从一个源文件中使用,那么它真的没有任何区别。
global
和local
可见性吗?public
在结构中没有意义。默认情况下,所有结构都是公共的。public
不是 C 中的关键字。如果您查看下面 Matthew Slattery 的回答,您会看到当用户尝试使用时,仅在标头中使用前向声明会导致编译器错误私有(不透明)结构的成员。