Haruskah definisi struct masuk dalam file .h atau .c?

102

Saya telah melihat definisi lengkap structs di header dan hanya deklarasi — adakah keuntungan dari satu metode dibandingkan yang lain?

Jika itu membuat perbedaan, saya biasanya mengetikkan struct seperti itu di .h

typedef struct s s_t;

Edit

Agar jelas, opsinya adalah deklarasi di file header dan definisi di kelas, atau deklarasi dan definisi di file header. Keduanya harus menghasilkan kegunaan yang sama, bahkan jika satu dengan keterkaitan, bukan?


Saya melihat banyak duplikat yang hampir sama, misalnya di sini tetapi tidak ada yang sama persis. Harap perbaiki saya jika saya salah dalam hal ini.

Aaron Yodaiken
sumber
2
Apakah Anda menginginkan struct buram atau non-buram?
4
Catatan tambahan, pengidentifikasi dengan _tdisediakan oleh POSIX, jadi ini biasanya ide yang buruk. Anda bisa melakukannya typedef struct toto toto.
Jens Gustedt
Saya telah melihat banyak _tpenggunaan di tempat lain (misalnya, lighttp, linux) ... dan saya mengawali sesuatu dengan projident_ jadi, itu seharusnya tidak menjadi masalah, bukan?
Aaron Yodaiken
Dan @WTP, saya pikir non-buram umumnya dianggap lebih baik dan lebih Cish, tidak (apa dengan FILEcontoh dll). Jadi, tidak buram.
Aaron Yodaiken
Jika ini adalah struct non-buram, ia harus masuk ke file header, atau kode Anda tidak KERING (jangan ulangi sendiri).

Jawaban:

107

Struktur privat untuk file itu harus berada dalam file .c, dengan deklarasi dalam file .h jika mereka digunakan oleh fungsi apa pun di .h.

Struktur publik harus masuk dalam file .h.

τεκ
sumber
4
Saya rasa saya lebih setuju dengan jawaban ini. Ini bukan tentang menggunakan struct melalui file .c lain atau tidak, ini tentang apakah struct harus dianggap publik (dan karenanya, dapat diakses) atau tidak.
c00kiemon5ter
@ τεκ Maksud Anda globaldan localvisibilitas? publictidak masuk akal dalam sebuah struct. Semua struct bersifat publik secara default.
BugShotGG
3
@Geo Papas Ini adalah pertanyaan tentang C. publicbukan kata kunci dalam C. Jika Anda melihat jawaban Matthew Slattery di bawah ini, Anda dapat melihat bagaimana hanya menggunakan deklarasi maju di tajuk yang menyebabkan kesalahan kompiler ketika pengguna mencoba menggunakan anggota a struct pribadi (buram).
τεκ
68

Keduanya harus menghasilkan kegunaan yang sama, bahkan jika satu dengan keterkaitan, bukan?

Tidak, tidak saat Anda mempertimbangkan file .c lain termasuk header yang sama. Jika definisi struktur tidak terlihat oleh kompiler, detail definisi tersebut tidak dapat digunakan. Sebuah deklarasi tanpa definisi (misalnya hanya struct s;) menyebabkan kompilator gagal jika ada yang mencoba untuk melihat ke dalam struct s, sementara masih mengizinkannya untuk, misalnya kompilasi struct s *foo;(selama footidak direferensikan nanti).

Bandingkan versi berikut dari api.hdan 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;          |
                                      | }                               |
                                      +---------------------------------+

Klien API ini bekerja dengan salah satu versi:

#include "api.h"

void good(struct s *foo)
{
    api_func(foo, 123);
}

Yang ini mengaduk-aduk detail implementasi:

#include "api.h"

void bad(struct s *foo)
{
    foo->internal = 123;
}

yang akan bekerja dengan versi "definisi dalam header", tetapi tidak dengan versi "definisi dalam implementasi", karena dalam kasus terakhir kompilator tidak memiliki visibilitas tata letak struktur:

$ gcc -Wall -c bad.c
bad.c: In function 'bad':
bad.c:5: error: dereferencing pointer to incomplete type
$

Jadi, versi "definisi dalam implementasi" melindungi dari penyalahgunaan detail implementasi pribadi yang tidak disengaja atau disengaja.

Matthew Slattery
sumber
3
hanya ingin tahu bagaimana Anda membuat jendela kode tersebut dan masih memiliki kode yang disorot di dalamnya ... secara manual? OP ini tampaknya telah pergi menggunakan stackoverflow: '(Adakah yang bisa memberi tahu saya ....
Mahesha999
Contoh yang bagus! Terima kasih!
Victor Haine
Terima kasih atas contoh seperti itu! dereferencing pointer to incomplete typeadalah kasus saya!
Timur Fayzrakhmanov
Saya hanya ingin menambahkan bahwa tidak semua struct yang dapat diakses publik itu buruk: Anda mungkin ingin mengaktifkan pengguna API Anda untuk mengisi data dan mengirimkannya.
Alexander Torstling
@ Mahesha999, tidak ada keajaiban di sana. SO menyoroti kode bahkan jika Anda menaruh sampah di dalamnya. Perhatikan itu mencoba untuk menyorot keluaran baris perintah nanti di pos.
Pemain sayap Sendon
8

Jika struct akan digunakan oleh unit kompilasi lain (file .c), letakkan di file header sehingga Anda dapat menyertakan file header itu dimanapun dibutuhkan.

Jika struct hanya digunakan dalam satu unit kompilasi (file .c), Anda menempatkannya di file .c tersebut.

no
sumber
3

Intinya adalah, menempatkannya di file header memungkinkan Anda menggunakan struktur (atau definisi lainnya) dari beberapa file sumber, hanya dengan memasukkan file header tersebut.

Tetapi jika Anda yakin itu hanya akan digunakan dari satu file sumber, maka tidak ada bedanya.

Jonathan Wood
sumber
-4

Secara umum, saya tidak berpikir itu membuat perbedaan besar apakah Anda meletakkannya di header atau file sumber. Namun, jika Anda perlu mengakses anggota struktur dari beberapa file sumber, akan lebih mudah untuk meletakkan struktur di file header dan menyertakannya dari file lain yang memerlukan struktur tersebut.

Frxstrem
sumber
8
-1: jika Anda peduli dengan rekayasa perangkat lunak yang baik (abstraksi, modularitas, dll) maka sebenarnya penting di mana Anda meletakkan definisi struct
Paul R