Domanda

Io sono abituato a fare tutto quello che la mia codifica in C di un file.Tuttavia, sto lavorando su un progetto abbastanza grande che diventa impraticabile per farlo.Sono stato #tra loro insieme, ma ho incontrato casi in cui sono #tra cui alcune più volte i file, etc.Ho sentito parlare di .h file, ma io non sono sicuro di quello che la loro funzione è (o perché avere 2 file è meglio di 1).

Quali le strategie da utilizzare per organizzare il mio codice?È possibile separare "pubblico" funzioni "privato" di quelli di un file particolare?

Questo domanda precipitato mia indagine.Il tè.h file non fa alcun riferimento al tè.c file.Fa il compilatore a "sapere" che ogni .h file ha un corrispondente .c il file?

È stato utile?

Soluzione

Si dovrebbe considerare .h i file come i file di interfaccia di la tua .c file.Ogni .c file rappresenta un modulo con una certa quantità di funzionalità.Se le funzioni in una .c file utilizzati da altri moduli (es.altri .file c) mettere la funzione di prototipo .h file di interfaccia.Includendo il file di interfaccia originale moduli .file in c e di tutte le altre .c file è necessario che la funzione, è rendere disponibile questa funzione anche per gli altri moduli.

Se avete solo bisogno di una funzione in un certo .file in c (non in qualsiasi altro modulo), dichiara che la sua portata statica.Questo significa che può essere chiamato solo da dentro il file c è definito.

Lo stesso vale per le variabili che vengono utilizzate su più moduli.Si dovrebbe andare per il file di intestazione e ci sono marcate con la parola chiave 'extern'.Nota:Per le funzioni che la parola chiave 'extern' è opzionale.Le funzioni sono sempre considerati 'extern'.

L'inclusione guardie nel file di intestazione aiutare a non includere la stessa intestazione file più volte.

Per esempio:

Module1.c:

    #include "Module1.h"

    static void MyLocalFunction(void);
    static unsigned int MyLocalVariable;    
    unsigned int MyExternVariable;

    void MyExternFunction(void)
    {
        MyLocalVariable = 1u;       

        /* Do something */

        MyLocalFunction();
    }

    static void MyLocalFunction(void)
    {
      /* Do something */

      MyExternVariable = 2u;
    }

Module1.h:

    #ifndef __MODULE1.H
    #define __MODULE1.H

    extern unsigned int MyExternVariable;

    void MyExternFunction(void);      

    #endif

Module2.c

    #include "Module.1.h"

    static void MyLocalFunction(void);

    static void MyLocalFunction(void)
    {
      MyExternVariable = 1u;
      MyExternFunction();
    }

Altri suggerimenti

Provate a fare ogni .c concentrarsi su una particolare area di funzionalità.Utilizzare il corrispondente .h a dichiarare tali funzioni.

Ogni .h il file deve avere un 'intestazione' di guardia intorno ad esso contenuto.Per esempio:

#ifndef ACCOUNTS_H
#define ACCOUNTS_H
....
#endif

Che modo è possibile includere conti".h" come molte volte come si desidera, e la prima volta che ha visto in una particolare unità di compilazione, sarà l'unico che effettivamente tira nel suo contenuto.

Compilatore

Si può vedere un esempio di un C 'module' a questo argomento - Si noti che ci sono due file - header di tè.h, e il codice di tè.c.Si dichiara tutto il pubblico definisce, le variabili e i prototipi di funzione che si desidera che altri programmi per accedere nell'intestazione.Nel progetto principale potrete #include e che il codice ora è possibile accedere a funzioni e variabili di tè modulo che sono citati nell'intestazione.

Diventa un po ' più complesso dopo che.Se si utilizza Visual Studio e molti altri Ide che gestire la tua build per voi, allora di ignorare questa parte - si prendono cura di compilazione e collegamento di oggetti.

Linker

Durante la compilazione di due distinti file C il compilatore produce i singoli file oggetto - in modo che i principali.c diventa principale.o e tè.c diventa tè.o.Il linker del lavoro è quello di cercare tutti i file oggetto (il principale.o e tè.o), e abbinare i riferimenti in modo che quando si chiama un tè funzione principale, il linker modifica chiamata così in realtà non chiamare la funzione del tè.Il linker produce il file eseguibile.

C'è un ottimo tutorial che va più in profondità su questo argomento, tra cui portata e l'altra questione che verrà eseguito in.

Buona fortuna!

-Adam

Un paio di semplici regole per iniziare:

  1. Mettere quelle dichiarazioni che si desidera rendere "pubblico" nel file di intestazione per l'implementazione C file che si sta creando.
  2. Solo #include file di intestazione nel file C che sono necessarie per attuare il C file.
  3. includere il file di intestazione in un file di intestazione solo se richiesto per le dichiarazioni all'interno di quel file di intestazione.

  4. Utilizza l'inclusione guardia metodo descritto da Andrea O utilizzare #pragma once se il compilatore supporta (che fa la stessa cosa-a volte in modo più efficiente)

Per rispondere alla tua domanda:

Questo domanda precipitato mia indagine.Il tè.h file non fa alcun riferimento alla tè.c file.Fa il compilatore a "sapere" che ogni .h file ha un corrispondente .c il file?

Il compilatore non è principalmente interessato con un file di intestazione.Ogni invocazione del compilatore compila un sorgente (.c) file in un oggetto.o) di file.Dietro le quinte (es.nel make file o file di progetto) una riga di comando equivalente a ciò che viene generato:

compiler --options tea.c

Il file di origine #includes tutti i file di intestazione per le risorse di riferimento, che è come il compilatore trova il file di intestazione.

(Sto trascurando un po ' nei dettagli.C'è molto da imparare circa la costruzione di progetti in C.)

Così come le risposte fornite in precedenza, un piccolo vantaggio di splintaggio codice in moduli (file separati) è che se tutte le variabili globali, è possibile limitare il loro ambito di un singolo modulo, l'uso della parola chiave 'statico'.(Si potrebbe anche applicare questo alle funzioni).Si noti che questo uso di 'statico', è diverso dal suo utilizzo all'interno di una funzione.

La tua domanda mette in chiaro che non si è veramente fatto molto grave di sviluppo.Il caso più frequente è che il codice sarà generalmente troppo grande per essere contenuto in un unico file.Una buona regola è che si deve dividere la funzionalità in unità logiche (.c) e i file di ogni file non deve contenere più di quello che si può facilmente tenere in testa in una sola volta.

Un dato prodotto software, quindi di solito comprende l'uscita di numerosi e diversi .c file.Come questo è fatto di solito è che il compilatore produce un numero di file oggetto (nei sistemi unix ".o" file, VC genera .i file obj).È lo scopo della "linker" per comporre i file oggetto in uscita (una libreria condivisa o eseguibile).

Generalmente l'implementazione (.c) i file che contengono codice eseguibile effettivo, mentre i file di intestazione (.h) dichiarazione delle funzioni pubbliche in quelle file di implementazione.Si può facilmente avere più file di intestazione che ci sono file di implementazione, e, a volte, i file di intestazione può contenere il codice in linea pure.

In generale è abbastanza insolito per l'attuazione file da includere ogni altro.Una buona pratica è quello di garantire che ogni file di implementazione separa le preoccupazioni da altri file.

Ti consiglierei di scaricare e guardare il sorgente per il kernel di linux.È abbastanza grande per un programma in C, ma ben organizzato in aree distinte di funzionalità.

L' .h i file devono essere utilizzati per definire i prototipi per le funzioni.Questo è necessario in modo che è possibile includere i prototipi che avete bisogno nella vostra C-file senza dichiarare ogni funzione di che cosa avete bisogno in un unico file.

Per esempio, quando si #include <stdio.h>, questo fornisce i prototipi di printf e altre funzioni IO.I simboli per queste funzioni sono normalmente caricato dal compilatore di default.È possibile guardare il sistema .h i file in /usr/include, se sei interessato a normale idiomi coinvolti con questi file.

Se stai solo scrivendo banali applicazioni con non molte funzioni, non è davvero necessario per modularizzare il tutto in raggruppamenti logici di procedure.Tuttavia, se avete la necessità di sviluppare un sistema di grandi dimensioni, quindi avrete bisogno di pagare una certa considerazione, per cui per definire tutte le funzioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top