Modulo C - Dove inserire prototipi e definizioni che non appartengono all'interfaccia pubblica?

3

Dato che sono principalmente un ingegnere elettrico, perdonami se ho qualche terminologia.

Attualmente sto programmando un driver di visualizzazione / modulo di interfaccia. E come tante altre volte, ho raggiunto un punto in cui non sono sicuro su come separare i prototipi di funzioni e definizioni che sono intese per uso interno del modulo dall'interfaccia pubblica .

Considera il seguente codice come esempio:

C-file:

// display.c
#include "display.h"

// Belongs to public Interface
void SetFont(Font_t fnt) {
    // implementation
}

// Belongs to public Interface
void PrintCharAt(int x, int y, char ch) {
    // implementation
}

// For internal use only 
void SendDataToDisplay(DisplayTelegram_t telegram) {

}

intestazione:

// display.h
typedef struct {
    // implementation
} Font_t;

typedef struct {
    // implementation
} DisplayTelegram_t;

void SetFont(Font_t fnt);
void PrintCharAt(int x, int y, char ch);
void SendDataToDisplay(DisplayTelegram_t telegram);

L'articolo Che cosa appartiene a un file di intestazione C? h? copre diversi punti con i quali sono maggiormente d'accordo.

DO include in the header file all of the function prototypes for the public interface of the module it describes.

DON’T include in the header file any other function or macro that may lie inside the module source code. It is desirable to hide these internal “helper” functions inside the implementation. If it’s not called from any other module, hide it!

Fin qui tutto bene, ma qual è la migliore pratica per nascondere i prototipi interni ecc? Non c'è motivo di avere il tipo DisplayTelegram_t e il prototipo SendDataToDisplay() nell'intestazione. Potrebbe anche confondere qualcuno che vuole solo utilizzare l'interfaccia quando le cose diventano più complesse.

Posso pensare a tre opzioni:

  1. Basta mettere tutti i prototipi interni, typedef, definisce ecc. in cima al file .c. L'ho fatto in passato, ma non mi piace. Non sembra coerente inquinare il file .c con il materiale dell'intestazione.

  2. Crea un secondo file di intestazione come display_internal.h e metti tutto lì solo per uso interno. Ho letto molto su questo approccio, ma l'ho visto a malapena.

  3. Non preoccuparti di nascondere i prototipi interni ecc. e basta mettere tutto nel file di intestazione. Magari raggruppando rispettivamente le cose pubbliche e quelle interne e lasciando un commento. Questo è sporco dal punto di vista della responsabilità, ma almeno è coerente e pulito per l'autore del codice.

C'è qualche approccio che mi manca? Come viene gestito a livello professionale?

    
posta Rev1.0 04.06.2015 - 14:35
fonte

1 risposta

4

1.Just put all internal prototypes, typedefs, defines etc. to the top of the .c-file. I have done this in the past, but I do not like it. It does not seem consistent to pollute the .c-file with header-material.

I prototipi di funzioni non sono intestazione-materiale. I prototipi di funzioni API pubbliche sono intestazione-materiale.

Se avessi una singola unità di compilazione, non avresti affatto bisogno del file di intestazione. Quindi, è possibile aggiungere tutti i prototipi (necessari in tale unità di compilazione per compilare) all'inizio del file C.

Puoi ancora farlo, ma dal momento che di solito hai più unità di compilazione e riutilizzano le rispettive API pubbliche, è logico che le API pubbliche siano in file separati, che vengono poi riutilizzati (evitando così il codice duplicato).

La tua seconda alternativa ( creare un secondo file di intestazione come display_internal.h e mettere tutto per uso interno solo lì ) non è realmente un'alternativa: nel momento in cui aggiungi i prototipi di funzione a un file di intestazione da usare in altre unità di compilazione, ovvero un'interfaccia pubblica per definizione (e dovrebbe trovarsi nell'intestazione dell'API pubblica).

La terza alternativa è negativa per la manutenzione del progetto (molto male!). In pratica, le persone che lavorano sul codice cliente, trovano i prototipi e calcolano "hey, sto facendo riutilizzo del codice;)" senza preoccuparsi che nell'intestazione ci sia un commento che dice "parte delle API private". In questo modo, finiscono per aggiungere interdipendenze non documentate su API private.

TLDR : la prima opzione è quella giusta da prendere.

    
risposta data 05.06.2015 - 09:43
fonte

Leggi altre domande sui tag