คำจำกัดความของโครงสร้างควรอยู่ในไฟล์. h หรือ. c?


102

ฉันเห็นทั้งคำจำกัดความแบบเต็มของstructs ในส่วนหัวและเพียงแค่การประกาศ - วิธีหนึ่งมีข้อดีกว่าวิธีอื่นหรือไม่

ถ้ามันสร้างความแตกต่างฉันมักจะพิมพ์โครงสร้างแบบนี้ในไฟล์ .h

typedef struct s s_t;

แก้ไข

เพื่อความชัดเจนอ็อพชันคือการประกาศในไฟล์ส่วนหัวและนิยามในคลาสหรือทั้งการประกาศและนิยามในไฟล์ส่วนหัว ทั้งสองอย่างควรส่งผลให้สามารถใช้งานได้เหมือนกันแม้ว่าจะมีการเชื่อมโยงกันก็ตาม


ฉันเห็นรายการเกือบซ้ำกันหลายรายการเช่นที่นี่แต่ไม่มีรายการที่ตรงกันทั้งหมด โปรดแก้ไขฉันหากฉันผิดในเรื่องนี้


2
คุณต้องการโครงสร้างทึบแสงหรือไม่ทึบแสง?

4
หมายเหตุข้างตัวระบุ_tถูกสงวนไว้โดย POSIX ดังนั้นจึงเป็นความคิดที่ไม่ดี typedef struct toto totoคุณก็สามารถทำ
Jens Gustedt

ฉันเคยเห็นการ_tใช้งานที่อื่นมากมาย (เช่น lighttp, linux) ... และฉันขึ้นต้นสิ่งต่างๆด้วย projident_ ดังนั้นมันไม่ควรเป็นปัญหาหรือไม่
Aaron Yodaiken

และ @WTP ฉันคิดว่าโดยทั่วไปแล้วการไม่ทึบแสงนั้นถือว่าดีกว่าและมากกว่าCนั้นไม่ใช่ (อะไรกับFILEตัวอย่าง ฯลฯ ) ดังนั้นไม่ทึบแสง
Aaron Yodaiken

หากเป็นโครงสร้างที่ไม่ทึบแสงจะต้องไปอยู่ในไฟล์ส่วนหัวไม่เช่นนั้นรหัสของคุณจะไม่แห้ง (อย่าทำซ้ำตัวเอง)

คำตอบ:


107

โครงสร้างส่วนตัวสำหรับไฟล์นั้นควรอยู่ในไฟล์. c โดยมีการประกาศในไฟล์. h หากใช้โดยฟังก์ชันใด ๆ ใน. h

โครงสร้างสาธารณะควรอยู่ในไฟล์. h


4
ฉันคิดว่าฉันเห็นด้วยกับคำตอบนี้มากกว่า ไม่ได้เกี่ยวกับการใช้โครงสร้างผ่านไฟล์. c อื่น ๆ หรือไม่ แต่โครงสร้างควรได้รับการพิจารณาว่าเป็นสาธารณะ (และเข้าถึงได้) หรือไม่
c00kiemon5ter

@ τεκคุณหมายถึงglobalและlocalทัศนวิสัย? publicไม่สมเหตุสมผลในโครงสร้าง โครงสร้างทั้งหมดเป็นสาธารณะโดยค่าเริ่มต้น
BugShotGG

3
@Geo Papas นี่คือคำถามเกี่ยวกับ C. publicไม่ใช่คีย์เวิร์ดใน C หากคุณดูคำตอบของ Matthew Slattery ด้านล่างคุณจะเห็นได้ว่าการใช้เพียงการประกาศไปข้างหน้าในส่วนหัวทำให้เกิดข้อผิดพลาดของคอมไพเลอร์เมื่อผู้ใช้พยายามใช้สมาชิกของ a โครงสร้างส่วนตัว (ทึบแสง)
τεκ

68

ทั้งสองอย่างควรส่งผลให้สามารถใช้งานได้เหมือนกันแม้ว่าจะมีการเชื่อมโยงกันก็ตาม

ไม่ไม่ใช่เมื่อคุณพิจารณาไฟล์. 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
$

ดังนั้นเวอร์ชัน "คำจำกัดความในการนำไปใช้งาน" จึงป้องกันการใช้รายละเอียดการติดตั้งแบบส่วนตัวโดยไม่ได้ตั้งใจหรือโดยเจตนา


3
แค่อยากรู้ว่าคุณสร้างหน้าต่างโค้ดเหล่านั้นได้อย่างไรและยังมีโค้ดที่ไฮไลต์อยู่ภายใน ... ด้วยตนเอง? OP นี้ดูเหมือนจะถูกทิ้งไว้โดยใช้ stackoverflow: '(ใครช่วยบอกฉันที ....
Mahesha999

เป็นตัวอย่างที่ดี! ขอบคุณ!
Victor Haine

ขอบคุณสำหรับตัวอย่างเช่น! dereferencing pointer to incomplete typeเป็นกรณีของฉัน!
Timur Fayzrakhmanov

ฉันอยากจะเพิ่มว่าโครงสร้างที่เข้าถึงได้แบบสาธารณะไม่ได้ทั้งหมดที่ไม่ดีตัวอย่างเช่นคุณอาจต้องการให้ผู้ใช้ API ของคุณกรอกข้อมูลและส่งเข้ามา
Alexander Torstling

@ Mahesha999 ไม่มีเวทมนตร์ที่นั่น SO ไฮไลต์โค้ดแม้ว่าคุณจะใส่ขยะลงไปก็ตาม สังเกตว่าพยายามไฮไลต์เอาต์พุตบรรทัดคำสั่งในภายหลังในโพสต์
Winger Sendon

8

หากต้องใช้โครงสร้างโดยหน่วยคอมไพล์อื่น (ไฟล์. c) ให้วางไว้ในไฟล์ส่วนหัวเพื่อให้คุณสามารถรวมไฟล์ส่วนหัวนั้นได้ทุกที่ที่ต้องการ

หากใช้ struct ในหน่วยคอมไพล์เดียวเท่านั้น (ไฟล์. c) ให้คุณวางไว้ในไฟล์. c นั้น


3

ประเด็นคือการวางไว้ในไฟล์ส่วนหัวทำให้คุณสามารถใช้โครงสร้าง (หรือคำจำกัดความอื่น ๆ ) จากไฟล์ต้นฉบับหลายไฟล์ได้เพียงแค่รวมไฟล์ส่วนหัวนั้น

แต่ถ้าคุณแน่ใจว่าจะใช้จากซอร์สไฟล์เดียวเท่านั้นจริงๆแล้วมันไม่ได้สร้างความแตกต่างใด ๆ


0

ฉันทำให้พวกเขาเป็นไฟล์ C ที่จะทำให้มันมากขึ้นวัตถุเชิงดูบทความนี้


-4

โดยทั่วไปฉันไม่คิดว่ามันสร้างความแตกต่างอย่างมากไม่ว่าคุณจะใส่ไว้ในไฟล์ส่วนหัวหรือไฟล์ต้นฉบับ อย่างไรก็ตามหากคุณต้องการเข้าถึงสมาชิกของโครงสร้างจากไฟล์ซอร์สหลายไฟล์การวางโครงสร้างในไฟล์ส่วนหัวจะง่ายกว่าและรวมเข้าจากไฟล์อื่น ๆ ที่ต้องการโครงสร้าง


8
-1: ถ้าคุณสนใจเกี่ยวกับวิศวกรรมซอฟต์แวร์ที่ดี (นามธรรมโมดูลาร์ ฯลฯ ) จริงๆแล้วมันก็สำคัญที่คุณใส่คำจำกัดความของโครงสร้าง
Paul R
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.