ทั้งสองอย่างควรส่งผลให้สามารถใช้งานได้เหมือนกันแม้ว่าจะมีการเชื่อมโยงกันก็ตาม
ไม่ไม่ใช่เมื่อคุณพิจารณาไฟล์. c อื่น ๆ ที่มีส่วนหัวเดียวกัน หากคอมไพลเลอร์มองไม่เห็นนิยามของโครงสร้างจะไม่สามารถใช้รายละเอียดของนิยามนั้นได้ การประกาศที่ไม่มีคำจำกัดความ (เช่น just 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
$
ดังนั้นเวอร์ชัน "คำจำกัดความในการนำไปใช้งาน" จึงป้องกันการใช้รายละเอียดการติดตั้งแบบส่วนตัวโดยไม่ได้ตั้งใจหรือโดยเจตนา