2017-12-09 11 views
-2

Ich habe ein C-Projekt und ich verstehe wirklich nicht, wie man .c und .h verwaltet. Ich habe eine Methode seit Jahren verwendet, aber jetzt muss ich Codes ohne Warnungen erstellen, also muss ich die Art ändern, wie ich es tue.Wie passt man .c und .h richtig an?

Hier ist, wie ich es so mache:

Jeder .c eine .h mit dem gleichen Namen haben. Sogar main.c hat ein main.h.

In jeder .c, schließe ich die passende .h, also habe ich nur eine Include pro .c. In main.h schließe ich alle Bibliotheken ein, die ich brauche, wie zB stdio stdlib und so weiter. Ich erkläre auch dort meine Aufzählungen und Strukturen.

Schließlich schließe ich in jeder anderen .h, die Main.h, die die Strukturen, enums und Bibliotheken enthält.

Ich verstehe das, indem ich main.h viel Zeit rufe, aber ich benutze die #ifndef und #define in jedem .h. Auch ich .h enthält jeweils die Prototypen der Funktionen in ihren entsprechenden .c

Wie soll ich .c und .h verwalten?

habe ich vergessen zu erwähnen, dass das Problem ist, dass ich eine Warnung für jede einzelne Funktion bekommen: „implizite Deklaration der Funktion“

Hier ist ein Beispiel mit vier Dateien:

main.c:

#include "main.h" 

int main() 
{ 
    // code 
} 
int save(Player players[2], int currentPlayer) 
{ 
    // code 
} 
int load(Player players[2], int* currentPlayer) 
{ 
    // code 
} 

main.h:

#ifndef MAIN_H 
#define MAIN_H 

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <windows.h> 
#include <string.h> 
#include <math.h> 

typedef enum Direction Direction; 
typedef enum Orientation Orientation; 
typedef enum ShipType ShipType; 
typedef enum CaseType CaseType; 
typedef enum Status Status; 
typedef enum PlayerType PlayerType; 

enum Direction 
{ 
    Nord=0, Est=1, Sud=2, Ouest=3 
}; 
enum Orientation 
{ 
    None=0, Horizontal=1, Vertical=2 
}; 
enum ShipType 
{ 
    SousMarin=1, Destroyer=2, Croiseur=3, Cuirasse=4 
}; 
enum CaseType 
{ 
    Undiscovered=0, Empty=1, Hit=2, Detected=3, Discovered=5 
}; 

enum Status 
{ 
    Undamaged=0, Damaged=1, Drowned=2 
}; 

enum PlayerType 
{ 
    Human=0, Computer=1 
}; 

typedef struct Map Map; 
typedef struct Ship Ship; 
typedef struct Player Player; 

struct Map 
{ 
    int width, height; 
    int* cases; 
}; 

struct Ship 
{ 
    int x, y, length, firstShoot, color; 
    int hasBeenDiscovered; 
    Orientation orientation; 
    ShipType type; 
    Status status; 
}; 

struct Player 
{ 
    int totalShips; 
    int activeShips; 
    Map map[2]; 
    char lastMoves[5][128]; 
    Ship* ships; 
    PlayerType type; 
    int shipcolor[4]; 
    int shipNumber[4]; 
    int color; 
}; 

int save(Player players[2], int currentPlayer); 
int load(Player players[2], int* currentPlayer); 

#endif // MAIN_H 

IA.c:

#include "IA.h" 

int IA(Player* IA, Player* enemy) 
{ 
    // code 
} 

// And all my other functions 

IA.h:

#ifndef IA_H 
#define IA_H 

#include "main.h" 

int IA(Player* IA, Player* enemy); 
void endIATurn(Player* IA); 

int enemyShipDiscovered(Map map, int* x, int* y, int SousMarinSpecific); 
Ship* bestFriendlyActiveShip(Ship* ships, int totalShips, int SousMarinSpecific); 
int friendlyShipDiscovered(Ship** ship, Ship* ships, Map map, int totalShips, int SousMarinSpecific); 
int hitShipButNotDrowned(Player* IA, Player enemy, int totalShips, int* x, int* y); 

int hasAtLeastOneMoveableShip(Player player); 
int hasUndiscoveredCases(Player player); 

void getUndiscoveredCoordoonnees(Map map, int* x, int* y); 
int findNextCaseToShootAt(Map map, Ship ship, int* a, int* b); 

#endif // IA_H 

All meine andere .h sind wie IA.h

+0

In Anbetracht der Art und Weise, wie Sie mit den Dateien umgehen, erwartete ich eher eine * doppelte * Deklaration ... Könnten wir einen Ausschnitt aus einem '.c' und dem dazugehörigen' .h' sehen? –

+1

Und Sie haben diese Warnungen für _years_ erhalten und nicht gedacht, bis jetzt etwas darüber zu tun? Wenn Sie eine "implizite Deklaration" haben, kann der Compiler die Deklaration zum Zeitpunkt, an dem eine Funktion aufgerufen wird, nicht sehen - irgendwie haben Sie den Header nicht eingefügt oder der Header ist nicht korrekt.Es ist bei weitem nicht klar aus Ihrer Textbeschreibung, was Sie tun; poste einige Beispiele. – Clifford

+1

post a [mcve] bitte – bolov

Antwort

2

Für foo.h und foo.c:

  • Verwenden foo.h andere Quelle zu sagen, Dateien über Dinge, die foo.c bietet. So deklariert foo.h Funktionen, die (a) in foo.c definiert sind und (b) aus anderen Quelldateien aufgerufen werden. Es deklariert auch alle Arten oder andere Dinge, die diese Funktionen benötigen oder die andere Quelldateien benötigen, um die Funktionen verwenden zu können.

  • Verwenden Sie in foo.h nur #include, um Header-Dateien einzuschließen, die foo.h selbst benötigt.

  • Verwenden Sie in foo.c#include "foo.h". Dies hat zwei Zwecke: (1) Es deklariert Dinge, die foo.c möglicherweise benötigen, ohne diese Deklarationen in foo.c duplizieren zu müssen.(2) Es stellt sicher, dass foo.c die gleichen Deklarationen verwendet, die andere Quelldateien sehen, wenn sie foo.h enthalten, so dass Konflikte zwischen Deklarationen in foo.h und Definitionen in foo.c Compilerwarnungen oder Fehlermeldungen erzeugen.

  • Wenn foo.c alle Header benötigt, die foo.h, gehören sie in foo.c, nicht foo.h. Wenn foo.c über Funktionen verfügt, die für sich selbst verwendet werden, andere Quelldateien jedoch nicht erwarten, deklarieren Sie sie nur in foo.c. Halten Sie Dinge, die nur für foo.c innerhalb foo.c sind. Verwenden Sie foo.h nur zum Exportieren von Dateien in andere Quelldateien.

Wenn es irgendwelche Arten oder andere Erklärungen von Ihrem Programm im Allgemeinen verwendet werden, sind:

  • Setzen Sie sie in einem entsprechend benannten Datei (zum Beispiel bar.h für Typen einige bar Konzept beteiligt) und schließen es. Hauptsächlich können Sie bar.h als ein Paar bar.h und bar.c oben beschrieben behandeln, außer dass bar.c leer ist.

Im Allgemeinen gibt es keinen Grund, eine main.h zu machen. Normalerweise verwendet main.c Dinge, die von anderen Quelldateien bereitgestellt werden, und bietet keine Funktionen für andere Quellen (außer dass main durch den C-Laufzeit-Startcode aufgerufen wird).

1

Ich schlage vor, die folgenden:

  1. Teilen Sie Ihre Funktionen in verschiedenen .c Dateien, wie Sie bereits tun. Für jede .c eine .h
  2. In jeder erstellen .h einfügen seine umfassen Wache:
    1. Innerhalb der Wache gehören zunächst die .h der Bibliotheken einschließlich Sie benötigen Ihre Funktionen declare oder um Strukturen zu definieren, z #include <stdlib.h> wenn Sie size_t Parameter verwenden.
    2. Innerhalb der Include-Guard, fügen Sie die Strukturen, enums, ... Sie müssen exportiert
    3. Innerhalb der Include-Guard, fügen Sie die Funktionsdeklarationen.
  3. Beginnen Sie in jedem .c mit der entsprechenden .h-Datei, fügen Sie dann weitere Bibliotheken hinzu, die zur Implementierung Ihrer Funktionen benötigt werden, und fügen Sie dann die Definitionen ein.
  4. Machen Sie keine main.h oder common.h, es sei denn, Sie haben extrem gute Gründe dafür (Ich weiß, dass dies gegen Kommentare kommen wird, aber jeder hat seinen Stil).

In main.c enthalten, was Sie brauchen. Sie werden viel weniger einschließen, als Sie denken.

+0

Wenn ich es richtig verstehe, muss ich in jeder .h meine Strukturen und enums einfügen (wenn ich sie in der .h) verwende? Ich kann sie nicht einfach einmal erklären? – Drakalex

+0

Ihre Frage sollte lauten: "Warum bekomme ich diese Fehler?" Und nicht "Wie organisiere ich meine Dateien?" - Letzteres hat wenig mit Ihren Fehlern zu tun und basiert weitgehend auf Meinungen. Wenn die Lösung die Dateiorganisation ist; Sie werden das in der Antwort bekommen - beantworten Sie nicht die Antworten, indem Sie nach einer bestimmten Lösung fragen - laden Sie stattdessen alle Lösungen ein. – Clifford

+1

@Drakalex: Jede Struktur oder Aufzählungstyp sollte nur in einer Kopfzeile definiert werden. Wenn andere Header diese Informationen ebenfalls benötigen, sollten diese Header den einzigen Header enthalten, der die Struktur oder die Enumeration definiert. Header-Wächter behandeln Restprobleme. Dies implementiert zwei Konzepte aus der agilen Entwicklung: SPOT - Single Point of Truth und DRY - Wiederhole dich nicht. Machen Sie jeden Header eigenständig (er kompiliert, ohne dass andere Header zuerst enthalten sind) und idempotent (es spielt keine Rolle, wie oft er enthalten ist; dafür stehen die Header-Wächter). –

Verwandte Themen