Sollten Strukturdefinitionen in die Datei .h oder .c aufgenommen werden?

102

Ich habe sowohl vollständige Definitionen von structs in Kopfzeilen als auch nur Deklarationen gesehen - hat eine Methode einen Vorteil gegenüber der anderen?

Wenn es einen Unterschied macht, schreibe ich normalerweise eine Struktur wie diese in die .h

typedef struct s s_t;

Bearbeiten

Um klar zu sein, sind die Optionen Deklaration in der Header-Datei und Definition in der Klasse oder sowohl Deklaration als auch Definition in der Header-Datei. Beide sollten zu der gleichen Benutzerfreundlichkeit führen, auch wenn eine durch Verknüpfung erfolgt, nicht wahr?


Ich sehe viele fast Duplikate, zB hier aber keine genauen Übereinstimmungen. Bitte korrigieren Sie mich, wenn ich diesbezüglich falsch liege.

Aaron Yodaiken
quelle
2
Möchten Sie eine undurchsichtige oder nicht undurchsichtige Struktur?
4
Nebenbei bemerkt, Bezeichner mit _twerden von POSIX reserviert, daher ist dies normalerweise eine schlechte Idee. Du könntest es einfach tun typedef struct toto toto.
Jens Gustedt
Ich habe viele _tandere Orte gesehen (z. B. LightTP, Linux) ... und ich stelle projident_ voran, also sollte das kein Problem sein, oder?
Aaron Yodaiken
Und @WTP, ich denke, dass nicht undurchsichtig im Allgemeinen als besser und mehr Cish angesehen wird, nein (was ist mit dem FILEBeispiel usw.). Also nicht undurchsichtig.
Aaron Yodaiken
Wenn es sich um eine nicht undurchsichtige Struktur handelt, muss sie in eine Header-Datei eingefügt werden, oder Ihr Code ist nicht DRY (wiederholen Sie sich nicht).

Antworten:

107

Private Strukturen für diese Datei sollten in der .c-Datei enthalten sein, mit einer Deklaration in der .h-Datei, wenn sie von Funktionen in der .h-Datei verwendet werden.

Öffentliche Strukturen sollten in die .h-Datei aufgenommen werden.

τεκ
quelle
4
Ich glaube, ich stimme dieser Antwort mehr zu. Es geht nicht darum, die Struktur über andere .c-Dateien zu verwenden oder nicht, es geht darum, ob die Struktur als öffentlich (und damit zugänglich) betrachtet werden soll oder nicht.
c00kiemon5ter
@ τεκ Meinst du globalund localSichtbarkeit? publicmacht in einer Struktur keinen Sinn. Alle Strukturen sind standardmäßig öffentlich.
BugShotGG
3
@Geo Papas Dies ist eine Frage zu C. publicist kein Schlüsselwort in C. Wenn Sie sich die Antwort von Matthew Slattery unten ansehen, können Sie sehen, dass die Verwendung nur einer Vorwärtsdeklaration im Header einen Compilerfehler verursacht, wenn der Benutzer versucht, Mitglieder von a zu verwenden private (undurchsichtige) Struktur.
τεκ
68

Beide sollten zu der gleichen Benutzerfreundlichkeit führen, auch wenn eine durch Verknüpfung erfolgt, nicht wahr?

Nein, nicht, wenn Sie andere .c-Dateien mit demselben Header berücksichtigen. Wenn die Definition der Struktur für den Compiler nicht sichtbar ist, können die Details dieser Definition nicht verwendet werden. Eine Deklaration ohne Definition (z. B. nur struct s;) führt dazu, dass der Compiler fehlschlägt, wenn etwas versucht, nach innen zu schauen struct s, während er z. B. kompiliert werden kann struct s *foo;(sofern dies foonicht später dereferenziert wird).

Vergleichen Sie diese Versionen von api.hund 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;          |
                                      | }                               |
                                      +---------------------------------+

Dieser Client der API funktioniert mit beiden Versionen:

#include "api.h"

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

Dieser stöbert in den Implementierungsdetails herum:

#include "api.h"

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

Dies funktioniert mit der Version "Definition in Header", jedoch nicht mit der Version "Definition in Implementierung", da der Compiler im letzteren Fall keine Sichtbarkeit des Layouts der Struktur hat:

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

Die Version "Definition in Implementierung" schützt also vor versehentlichem oder absichtlichem Missbrauch privater Implementierungsdetails.

Matthew Slattery
quelle
3
Sie möchten nur wissen, wie Sie diese Codefenster erstellt haben und trotzdem Code in ihnen hervorgehoben haben ... manuell? Dieses OP scheint Stackoverflow verwendet zu haben: '(Kann mir jemand anderes sagen ...
Mahesha999
Schönes Beispiel! Vielen Dank!
Victor Haine
Vielen Dank für ein solches Beispiel! dereferencing pointer to incomplete typewar genau mein Fall!
Timur Fayzrakhmanov
Ich möchte nur hinzufügen, dass nicht alle öffentlich zugänglichen Strukturen schlecht sind: Sie möchten beispielsweise dem Benutzer Ihrer API ermöglichen, Daten
einzugeben
@ Mahesha999, da ist keine Magie. SO hebt Code hervor, selbst wenn Sie Müll hineinlegen. Beachten Sie, dass versucht wird, die Befehlszeilenausgabe später im Beitrag hervorzuheben.
Flügelspieler Sendon
8

Wenn die Struktur von anderen Kompilierungseinheiten (.c-Dateien) verwendet werden soll, platzieren Sie sie in der Header-Datei, damit Sie diese Header-Datei überall dort einfügen können, wo sie benötigt wird.

Wenn die Struktur nur in einer Kompilierungseinheit (.c-Datei) verwendet wird, platzieren Sie sie in dieser .c-Datei.

nr
quelle
3

Der Punkt ist, dass Sie durch Platzieren in einer Header-Datei die Struktur (oder eine andere Definition) aus mehreren Quelldateien verwenden können, indem Sie einfach diese Header-Datei einschließen.

Aber wenn Sie sicher sind, dass es nur aus einer Quelldatei verwendet wird, macht es wirklich keinen Unterschied.

Jonathan Wood
quelle
-4

Im Allgemeinen denke ich nicht, dass es einen großen Unterschied macht, ob Sie sie in den Header oder in die Quelldateien einfügen. Wenn Sie jedoch von mehreren Quelldateien aus auf die Mitglieder einer Struktur zugreifen müssen, ist es einfacher, die Struktur in eine Header-Datei einzufügen und sie aus anderen Dateien aufzunehmen, in denen die Struktur benötigt wird.

Frxstrem
quelle
8
-1: Wenn Sie sich für gutes Software-Engineering interessieren (Abstraktion, Modularität usw.), spielt es tatsächlich eine Rolle, wo Sie die Strukturdefinition platzieren
Paul R