Her ikisi de aynı kullanılabilirlikle sonuçlanmalı, biri bağlantı yoluyla olsa bile, değil mi?
Hayır, aynı başlığı içeren diğer .c dosyalarını düşündüğünüzde değil. Yapının tanımı derleyiciye görünür değilse, bu tanımın ayrıntıları kullanılamaz. Tanımsız bir bildirim (örneğin sadece struct s;
), derleyicinin içeri bakmaya çalışırsa başarısız olmasına neden struct s
olurken, örneğin derlemesine izin verir struct s *foo;
( foo
daha sonra başvurulmadığı sürece ).
Şu api.h
ve 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; |
| } |
+---------------------------------+
Bu API istemcisi her iki sürümde de çalışır:
#include "api.h"
void good(struct s *foo)
{
api_func(foo, 123);
}
Bu, uygulama ayrıntılarında dolaşıyor:
#include "api.h"
void bad(struct s *foo)
{
foo->internal = 123;
}
Bu, "başlıktaki tanım" sürümüyle çalışacak, ancak "uygulamadaki tanım" sürümüyle çalışmayacaktır, çünkü ikinci durumda derleyici yapının düzenini görmez:
$ gcc -Wall -c bad.c
bad.c: In function 'bad':
bad.c:5: error: dereferencing pointer to incomplete type
$
Bu nedenle, "uygulamadaki tanım" versiyonu, özel uygulama ayrıntılarının yanlışlıkla veya kasıtlı olarak kötüye kullanılmasına karşı koruma sağlar.