どちらを使用しても、どちらかが同じユーザビリティになるはずです。1つがリンケージによるものであっても、そうではありませんか。
いいえ、同じヘッダーを含む他の.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
$
したがって、「実装の定義」バージョンは、プライベートな実装の詳細の偶発的または意図的な誤用から保護します。