Czy definicje struktur powinny znajdować się w pliku .h czy .c?

102

Widziałem zarówno pełne definicje structs w nagłówkach, jak i same deklaracje - czy jest jakaś przewaga jednej metody nad drugą?

Jeśli to robi różnicę, zwykle wpisuję taką strukturę w .h

typedef struct s s_t;

Edytować

Dla jasności, opcje to deklaracja w pliku nagłówkowym i definicja w klasie lub zarówno deklaracja, jak i definicja w pliku nagłówkowym. Oba powinny skutkować taką samą użytecznością, nawet jeśli jest to połączenie, prawda?


Widzę wiele prawie duplikatów, np. Tutaj, ale nie ma dokładnych dopasowań. Proszę mnie poprawić, jeśli się mylę w tej kwestii.

Aaron Yodaiken
źródło
2
Czy chcesz nieprzezroczystej lub niekryjącej struktury?
4
Na marginesie, identyfikatory z _tsą zarezerwowane przez POSIX, więc jest to zwykle zły pomysł. Możesz po prostu zrobić typedef struct toto toto.
Jens Gustedt
Widziałem wiele _tzastosowań innych miejsc (np. Lighttp, linux) ... i przedrostuję rzeczy z projident_, więc to nie powinno być problemem, prawda?
Aaron Yodaiken
I @WTP, myślę, że nieprzezroczysty jest ogólnie uważany za lepszy i bardziej Cish, nie (co z FILEprzykładem itp.). Więc nie-nieprzezroczysty.
Aaron Yodaiken
Jeśli jest to struktura nieprzezroczysta, musi zostać umieszczona w pliku nagłówkowym lub twój kod nie jest SUCHY (nie powtarzaj tego).

Odpowiedzi:

107

Struktury prywatne tego pliku powinny znajdować się w pliku .c, z deklaracją w pliku .h, jeśli są używane przez jakąkolwiek funkcję w .h.

Struktury publiczne powinny znajdować się w pliku .h.

τεκ
źródło
4
Myślę, że bardziej zgadzam się z tą odpowiedzią. Nie chodzi o używanie struktury przez jakiekolwiek inne pliki .c, czy nie, chodzi o to, czy struktura powinna być uznana za publiczną (a więc dostępną), czy nie.
c00kiemon5ter
@ τεκ Czy masz na myśli globali localwidoczność? publicnie ma sensu w strukturze. Wszystkie struktury są domyślnie publiczne.
BugShotGG,
3
@Geo Papas To jest pytanie dotyczące C. publicnie jest słowem kluczowym w C. Jeśli spojrzysz na odpowiedź Matthew Slattery'ego poniżej, zobaczysz, że użycie tylko deklaracji do przodu w nagłówku powoduje błąd kompilatora, gdy użytkownik próbuje użyć członków prywatna (nieprzezroczysta) struktura.
τεκ
68

Oba powinny skutkować taką samą użytecznością, nawet jeśli jest to połączenie, prawda?

Nie, nie biorąc pod uwagę innych plików .c zawierających ten sam nagłówek. Jeśli definicja struktury nie jest widoczna dla kompilatora, nie można użyć szczegółów tej definicji. Deklaracja bez definicji (np. Po prostu struct s;) powoduje niepowodzenie kompilatora, jeśli cokolwiek próbuje zajrzeć do środka struct s, jednocześnie pozwalając mu np. Na kompilację struct s *foo;(o ile foonie zostanie później dereferencjonowana).

Porównaj te wersje api.hi 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;          |
                                      | }                               |
                                      +---------------------------------+

Ten klient interfejsu API działa z dowolną wersją:

#include "api.h"

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

Ten przegląda szczegóły implementacji:

#include "api.h"

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

który będzie działał z wersją "definicja w nagłówku", ale nie z wersją "definicja w implementacji", ponieważ w tym drugim przypadku kompilator nie ma widoczności układu struktury:

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

Tak więc wersja „definicja we wdrożeniu” chroni przed przypadkowym lub umyślnym niewłaściwym wykorzystaniem prywatnych szczegółów implementacji.

Matthew Slattery
źródło
3
chcesz tylko wiedzieć, jak utworzyłeś te okna kodu i nadal masz w nich podświetlony kod ... ręcznie? Wydaje się, że ten OP pozostał przy użyciu stackoverflow: „(Czy ktoś może mi powiedzieć…
Mahesha999
Niezły przykład! Dzięki!
Victor Haine
Dziękuję za taki przykład! dereferencing pointer to incomplete typebył dokładnie w moim przypadku!
Timur Fayzrakhmanov
Chciałbym tylko dodać, że nie wszystkie publicznie dostępne struktury są złe: możesz na przykład chcieć umożliwić użytkownikowi twojego API wypełnianie danych i wysyłanie ich.
Alexander Torstling,
@ Mahesha999, nie ma tam żadnej magii. SO podkreśla kod, nawet jeśli umieścisz w nim śmieci. Zauważ, że próbuje podświetlić wyjście wiersza poleceń w dalszej części postu.
Skrzydłowy Sendon
8

Jeśli struktura ma być używana przez inne jednostki kompilacji (pliki .c), umieść ją w pliku nagłówkowym, abyś mógł dołączyć ten plik nagłówkowy tam, gdzie jest potrzebny.

Jeśli struktura jest używana tylko w jednej jednostce kompilacji (plik .c), należy umieścić ją w tym pliku .c.

nr
źródło
3

Chodzi o to, że umieszczenie go w pliku nagłówkowym umożliwia użycie struktury (lub dowolnej innej definicji) z wielu plików źródłowych, po prostu przez dołączenie tego pliku nagłówkowego.

Ale jeśli masz pewność, że zostanie użyty tylko z jednego pliku źródłowego, to naprawdę nie robi to żadnej różnicy.

Jonathan Wood
źródło
-4

Generalnie nie sądzę, aby miało to duże znaczenie, czy umieścisz je w nagłówku czy w plikach źródłowych. Jeśli jednak potrzebujesz uzyskać dostęp do elementów struktury z wielu plików źródłowych, łatwiej jest umieścić strukturę w pliku nagłówkowym i dołączyć ją z innych plików, w których jest potrzebna.

Frxstrem
źródło
8
-1: jeśli zależy Ci na dobrej inżynierii oprogramowania (abstrakcji, modułowości, etc), to faktycznie ma znaczenia, gdzie można umieścić definicję struct
Paul R