Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

A quoi servent les fichiers .h en C++ ?

14 réponses
Avatar
MYSELF
Bonjour,

Je me posais une question existencielle, à savoir "à quoi servent
exactement les fichiers .h en C++ ?"

Je sais bien que ce sont les headers et qu'on doit y inscrire les
prototypes des fonctions et méthodes des classes créées, mais je me
pose cette question parce qu'en C-Sharp par exemple, les classes sont
entièrement décrites dans les fichiers .cs, et il n'y a pas de fichiers
.h (à ce que je sache).
Il y a aussi d'autres langages tels que Java où on se passe fort bien
de fichiers .h.


D'où ma question : "A quoi servent exactement les fichiers .h en C++ ?"

Quel est l'avantage d'utiliser ces fichiers par rapport à d'autres
langages qui ne les utilisent pas ? Parce que j'imagine que si on les a
créés, c'est bien pour une raison ...

Merci.

10 réponses

1 2
Avatar
Fabien LE LEZ
On Mon, 16 Feb 2009 16:28:40 +0100, MYSELF :

Quel est l'avantage d'utiliser ces fichiers par rapport à d'autres
langages qui ne les utilisent pas ?



Pourquoi des .h en C++ ? Simple : parce que des fichiers .h en C.

Maintenant, pourquoi utilise-t-on ce système en C ?
Parce que ce langage est très très vieux. À l'époque, les machines
disposaient de très peu de mémoire ; il n'était pas imaginable de
gérer plus d'un seul module (.c). Les .h ne sont qu'une astuce pour
inclure du code dans plusieurs .c. (Note que le compilo ne voit qu'un
seul fichier -- tout #include est remplacé par le contenu du .h par le
préprocesseur.)
Avatar
pjb
MYSELF writes:
Je me posais une question existencielle, à savoir "à quoi servent
exactement les fichiers .h en C++ ?"

Je sais bien que ce sont les headers et qu'on doit y inscrire les
prototypes des fonctions et méthodes des classes créées, mais je me
pose cette question parce qu'en C-Sharp par exemple, les classes sont
entièrement décrites dans les fichiers .cs, et il n'y a pas de
fichiers .h (à ce que je sache).
Il y a aussi d'autres langages tels que Java où on se passe fort bien
de fichiers .h.


D'où ma question : "A quoi servent exactement les fichiers .h en C++ ?"

Quel est l'avantage d'utiliser ces fichiers par rapport à d'autres
langages qui ne les utilisent pas ? Parce que j'imagine que si on les
a créés, c'est bien pour une raison ...



Techniquement, en C ou C++, les .h ne servent à rien. On pourrait
s'en passer entièrement.

Simplement, ce serait un peu laborieux de déclarer tous les objets
externes qu'on utilise. Pour gagner du temps, on met les déclarations
dans des fichiers .h, et on utilise le pre-processeur C pour faire un
copier-coller au moment de la compilation.

La principale différence entre C et C++ d'une part et des langages
comme Modula-3, Java ou C#, c'est qu'il n'y a pas de notion de module
en C et C++. Dans le cas de langages comme Modula-2, Modula-3, on
peut définir l'interface d'un module séparément, ce qui offre
l'avantage de pouvoir compiler ces interfaces, ainsi de pouvoir les
utiliser de façon plus efficace lors de la compilation séparée des
modules clients. Comme extension, certains compilateurs C, C++,
Objective-C sont capables de précompiler des fichier .h, à condition
que ceux ci soient bien formés (et par exemple, qu'on ne s'amuse pas à
les inclure avec des valeurs de macro différentes de lors de leur
compilation). Mais cet avantage n'est pas défini par le langage C ou
C++, c'est seulement une optimisation bricolée par certains
compilateurs.

Comme indiqué par Fabien, pour ce qui est de langages comme Java ou C#
qui ne permettent pas (ou avec lesquels on ne le fait pas de manière
habituelle) de définir les interfaces de façon séparés, ça implique
qu'il faille traiter tout le module utilisé avant de traiter le module
client. Mais comme les ordinateurs actuels sont plus rapides et ont
plus de mémoire, ce n'est normalement pas un problème.


Donc, en C ou C++, on ne peut pas se passer en pratique des .h parce
que ces langages n'ont pas de notion de module.

Note que gcc a une option -combine qui permet de traiter plusieurs
sources d'un seul morceau. Ça permet de se passer de fichier
d'entête, à condition de copier toutes les déclarations des entêtes
système dans un fichier source (on peut admettre de le faire avec des
#include <> juste pour les entêtes système). Ce qui n'empêche qu'il
faille déclarer à l'avance les signatures des fonctions, etc.

--
__Pascal Bourguignon__
Avatar
James Kanze
On Feb 16, 4:28 pm, MYSELF wrote:
Je me posais une question existencielle, à savoir "à quoi
servent exactement les fichiers .h en C++ ?"



Dans la pratique, ils servent à implémenter ou émuler des
modules dans d'autres langages.

Je sais bien que ce sont les headers et qu'on doit y inscrire
les prototypes des fonctions et méthodes des classes créées,
mais je me pose cette question parce qu'en C-Sharp par
exemple, les classes sont entièrement décrites dans les
fichiers .cs, et il n'y a pas de fichiers .h (à ce que je
sache). Il y a aussi d'autres langages tels que Java où on se
passe fort bien de fichiers .h.



En effet, c'est un défaut majeur de ces langages, qui en rend
l'utilisation problèmmatique dans un projet un peu gros.

En fait, le défaut, ce n'est pas l'absence des fichiers
d'en-tête ; c'est l'absence d'un moyen de séparer
l'implémentation de la spécification en général. Tout compte
fait, l'inclusion textuelle est peut-être le pire moyen de
résoudre le problème (et crée pas mal de problèmes par
ailleurs), mais c'est toujours mieux que pas de solution du
tout. (Pour un exemple d'une bonne solution, voir Modula-2, ou,
je crois, Ada, mais je ne le connais pas bien.)

D'où ma question : "A quoi servent exactement les fichiers .h
en C++ ?"



Quel est l'avantage d'utiliser ces fichiers par rapport à
d'autres langages qui ne les utilisent pas ? Parce que
j'imagine que si on les a créés, c'est bien pour une raison
...



L'historique diffère de la réalité actuelle. Aujourd'hui, on les
utilise surtout pour similuer la partie spécification d'une
module. Dès que le projet dépasse une certaine taille, il
devient important de maintenir la spécification dans un fichier
à part, séparé des fichiers qui l'implément. Certains langages,
comme Smalltalk, contourne le problème en se passant d'une
spécification complétement -- les vérifications (de type, par
exemple) ne se font qu'à l'exécution. Dans Java, et d'après ce
que je crois comprendre, C#, la spécification est dérivée de
l'implémentation par le compilateur. Ce qui est l'inverse de
ce qu'on veut -- il faut la spécification avant de commencer
l'implémentation (et d'autres doivent pouvoir programmer avec la
spécification, avant qu'elle soit implémentée).

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
No_Name
James Kanze avait énoncé :
On Feb 16, 4:28 pm, MYSELF wrote:
Je me posais une question existencielle, à savoir "à quoi
servent exactement les fichiers .h en C++ ?"



Dans la pratique, ils servent à implémenter ou émuler des
modules dans d'autres langages.

Je sais bien que ce sont les headers et qu'on doit y inscrire
les prototypes des fonctions et méthodes des classes créées,
mais je me pose cette question parce qu'en C-Sharp par
exemple, les classes sont entièrement décrites dans les
fichiers .cs, et il n'y a pas de fichiers .h (à ce que je
sache). Il y a aussi d'autres langages tels que Java où on se
passe fort bien de fichiers .h.



En effet, c'est un défaut majeur de ces langages, qui en rend
l'utilisation problèmmatique dans un projet un peu gros.

En fait, le défaut, ce n'est pas l'absence des fichiers
d'en-tête ; c'est l'absence d'un moyen de séparer
l'implémentation de la spécification en général. Tout compte
fait, l'inclusion textuelle est peut-être le pire moyen de
résoudre le problème (et crée pas mal de problèmes par
ailleurs), mais c'est toujours mieux que pas de solution du
tout. (Pour un exemple d'une bonne solution, voir Modula-2, ou,
je crois, Ada, mais je ne le connais pas bien.)

D'où ma question : "A quoi servent exactement les fichiers .h
en C++ ?"



Quel est l'avantage d'utiliser ces fichiers par rapport à
d'autres langages qui ne les utilisent pas ? Parce que
j'imagine que si on les a créés, c'est bien pour une raison
...



L'historique diffère de la réalité actuelle. Aujourd'hui, on les
utilise surtout pour similuer la partie spécification d'une
module. Dès que le projet dépasse une certaine taille, il
devient important de maintenir la spécification dans un fichier
à part, séparé des fichiers qui l'implément. Certains langages,
comme Smalltalk, contourne le problème en se passant d'une
spécification complétement -- les vérifications (de type, par
exemple) ne se font qu'à l'exécution. Dans Java, et d'après ce
que je crois comprendre, C#, la spécification est dérivée de
l'implémentation par le compilateur. Ce qui est l'inverse de
ce qu'on veut -- il faut la spécification avant de commencer
l'implémentation (et d'autres doivent pouvoir programmer avec la
spécification, avant qu'elle soit implémentée).



Merci à tous pour vos réponses.
Je suis juste surpris de voir qu'un langage comme le C#, qui était
censé être "mieux pensé" que le C++ puisque créé plus tard et se basant
-en partie- sur le C++, n'a pas prévu de moyen de gérer cette
spécification à part ...
Avatar
pjb
No_Name writes:
L'historique diffère de la réalité actuelle. Aujourd'hui, on les
utilise surtout pour similuer la partie spécification d'une
module. Dès que le projet dépasse une certaine taille, il
devient important de maintenir la spécification dans un fichier
à part, séparé des fichiers qui l'implément. Certains langages,
comme Smalltalk, contourne le problème en se passant d'une
spécification complétement -- les vérifications (de type, par
exemple) ne se font qu'à l'exécution. Dans Java, et d'après ce
que je crois comprendre, C#, la spécification est dérivée de
l'implémentation par le compilateur. Ce qui est l'inverse de
ce qu'on veut -- il faut la spécification avant de commencer
l'implémentation (et d'autres doivent pouvoir programmer avec la
spécification, avant qu'elle soit implémentée).



Merci à tous pour vos réponses.
Je suis juste surpris de voir qu'un langage comme le C#, qui était
censé être "mieux pensé" que le C++ puisque créé plus tard et se
basant -en partie- sur le C++, n'a pas prévu de moyen de gérer cette
spécification à part ...



Il est vrai qu'avec une approche de haut-en-bas, on veut écrire
l'interface avant d'écrire l'implémentation (et même dans le cas de
modules compliqués, on peut écrire une implémentation bidon permettant
de tester les modules clients avant d'avoir fini l'implémentation
définitive).

Mais ceci n'empêche pas à priori de définir l'interface dans le même
source que l'implémentation, et d'utiliser des outils pour en extraire
la synthèse, tant que le source peut se "compiler" sans
l'implémentation.

C'est à dire que ça ne me choquerait pas de voir un source contenant:

void Module1_initialize(const char* initparameter)
/*
Documentation de la fonction...
*/
{
NOT_IMPLEMENTED_YET();
}

int Module1_function42(float x,int y){
/*
Documentation de la fonction...
*/
NOT_IMPLEMENTED_YET();
return(0);
}

et de générer automatiquement le fichier entête et la documentation à
partir de ce source. C'est ce qui est fait en Java.

C'est en fait exactement comme celà que je procédais quand je
programmais encore en C (et dans ma programmation C++ actuelle, les
fichiers entêtes sont en fait entièrement générés par Objecteering).
Dans certains projets, même les fichiers d'exemple de configuration et
la documentation utilisateur étaient générés à partir du source.

Le gros avantage étant de concentrer en un seul endroit toutes les
informations sur une fonction. Sans celà, quand on modifie
l'interface d'une fonction il faut toucher à trois fichiers (entête,
source, documentation), ce qui n'est jamais fait dans l'urgence et on
se retrouve avec des incohérences et des documentations pas à jour.

--
__Pascal Bourguignon__
Avatar
espie
In article <gndv0n$4k8$, No_Name wrote:
Merci à tous pour vos réponses.
Je suis juste surpris de voir qu'un langage comme le C#, qui était
censé être "mieux pensé" que le C++ puisque créé plus tard et se basant
-en partie- sur le C++, n'a pas prévu de moyen de gérer cette
spécification à part ...



Il ne faut pas croire toute la propagande du departement commercial de
Microsoft.

Si on regarde C#, du point de vue de Microsoft, son principal avantage
c'est de permettre de garder les gens encore un moment sur la plateforme
Windows. Il se presente comme un equivalent de Java, avec une interface
"plus propre" avec le systeme, et plus efficace (le fait que les
implementations Java pondues par microsoft soient subtilement inefficaces
n'est bien sur qu'une coincidence sans rapport). Le danger est bien reel:
si les gens commencent a ecrire du code qui tourne sur toutes les plateformes,
ils risqueraient de se rendre compte qu'ils peuvent vivre loin de Windows,
et qu'ils peuvent utiliser des bases de donnees autres qu'Access.

A cote de ca, il y a un reel effort des equipes "securite" de microsoft pour
faire avancer les choses... y compris en C++. C'est pas pour rien qu'ils
ont embauche Herb Sutter.

Mais F#, l'equivalent fonctionnel de C# au-dessus de la meme machine
virtuelle, avait l'air sensiblement plus interessant...
Avatar
Wykaaa
Marc Espie a écrit :
In article <gndv0n$4k8$, No_Name wrote:
Merci à tous pour vos réponses.
Je suis juste surpris de voir qu'un langage comme le C#, qui était
censé être "mieux pensé" que le C++ puisque créé plus tard et se basant
-en partie- sur le C++, n'a pas prévu de moyen de gérer cette
spécification à part ...



Il ne faut pas croire toute la propagande du departement commercial de
Microsoft.

Si on regarde C#, du point de vue de Microsoft, son principal avantage
c'est de permettre de garder les gens encore un moment sur la plateforme
Windows. Il se presente comme un equivalent de Java, avec une interface
"plus propre" avec le systeme, et plus efficace (le fait que les
implementations Java pondues par microsoft soient subtilement inefficaces
n'est bien sur qu'une coincidence sans rapport). Le danger est bien reel:
si les gens commencent a ecrire du code qui tourne sur toutes les plateformes,
ils risqueraient de se rendre compte qu'ils peuvent vivre loin de Windows,
et qu'ils peuvent utiliser des bases de donnees autres qu'Access.



;-)


A cote de ca, il y a un reel effort des equipes "securite" de microsoft pour
faire avancer les choses... y compris en C++. C'est pas pour rien qu'ils
ont embauche Herb Sutter.

Mais F#, l'equivalent fonctionnel de C# au-dessus de la meme machine
virtuelle, avait l'air sensiblement plus interessant...



Comment se fait-il qu'il y ait des travaux intéressants dans le
laboratoire de recherche de Microsoft, par exemple les travaux de Yuri
Gurevich sur les machines abstraites à états avec AsmL: The Abstract
State Machine Language
(www-madlener.informatik.uni-kl.de/teaching/ss2004/fsvt/14.05.04.main.b.pdf)
et que, au final, leurs produits logiciels ne soient pas au top (c'est
un euphémisme...). Ceci dit, XASM est une implémentation "open source"
de ce langage.

C# a été développé après le procès que Microsoft a perdu avec Sun à
propos de Java (l'implémentation de la JVM de Microsoft était liée à
Windows : appel direct à des routines du système dans la JVM) et qu'il
ait dû retirer tout ce qui concernait Java dans les 3 mois après le
jugement.
C# n'est qu'une copie de Java (avec amélioration de certains de ses
défauts les plus flagrants comme le fait que les types de base ne sont
pas des classes).
Avatar
pjb
(Marc Espie) writes:
A cote de ca, il y a un reel effort des equipes "securite" de microsoft pour
faire avancer les choses... y compris en C++. C'est pas pour rien qu'ils
ont embauche Herb Sutter.



Ah oui? Le runtime ed leur compilateur C++ détecte maintenant l'erreur
sur la ligne p[9]=0; ?

int main(){
char buffer[8];
char* p=buffer;
p[9]=0;
return(0);
}

Parce PAQJS que le standard C++, tout comme le standard C, n'autorise
pas cet accès, et n'interdit pas aux compilateurs de générer le code
nécessaire pour le vérifier.

--
__Pascal Bourguignon__
Avatar
James Kanze
On Feb 17, 11:10 am, (Pascal J. Bourguignon)
wrote:
No_Name writes:
>> L'historique diffère de la réalité actuelle. Aujourd'hui,
>> on les utilise surtout pour similuer la partie
>> spécification d'une module. Dès que le projet dépasse une
>> certaine taille, il devient important de maintenir la
>> spécification dans un fichier à part, séparé des fichiers
>> qui l'implément. Certains langages, comme Smalltalk,
>> contourne le problème en se passant d'une spécification
>> complétement -- les vérifications (de type, par exemple) ne
>> se font qu'à l'exécution. Dans Java, et d'après ce que je
>> crois comprendre, C#, la spécification est dérivée de
>> l'implémentation par le compilateur. Ce qui est l'inverse
>> de ce qu'on veut -- il faut la spécification avant de
>> commencer l'implémentation (et d'autres doivent pouvoir
>> programmer avec la spécification, avant qu'elle soit
>> implémentée).



> Merci à tous pour vos réponses.
> Je suis juste surpris de voir qu'un langage comme le C#, qui
> était censé être "mieux pensé" que le C++ puisque créé plus
> tard et se basant -en partie- sur le C++, n'a pas prévu de
> moyen de gérer cette spécification à part ...



Il est vrai qu'avec une approche de haut-en-bas, on veut
écrire l'interface avant d'écrire l'implémentation (et même
dans le cas de modules compliqués, on peut écrire une
implémentation bidon permettant de tester les modules clients
avant d'avoir fini l'implémentation définitive).



Mais ceci n'empêche pas à priori de définir l'interface dans
le même source que l'implémentation, et d'utiliser des outils
pour en extraire la synthèse, tant que le source peut se
"compiler" sans l'implémentation.



C'est à dire que ça ne me choquerait pas de voir un source
contenant:



void Module1_initialize(const char* initparameter)
/*
Documentation de la fonction...
*/
{
NOT_IMPLEMENTED_YET();
}



int Module1_function42(float x,int y){
/*
Documentation de la fonction...
*/
NOT_IMPLEMENTED_YET();
return(0);
}



et de générer automatiquement le fichier entête et la
documentation à partir de ce source. C'est ce qui est fait en
Java.



Ce qui ne résoud pas le problème que la spécification et
l'implémentation se trouve dans le même fichier. Dans les gros
projets en Java, on a souvent une règle que les clients
n'utilise que les interfaces, et que les objets réels soient
tous créés par des factories, de façon à ce que les interfaces
soient découplées des implémentations. Mais ça ne marche qu'à
moitié, parce que l'« interface » de Java ne permet pas à
définir assez la spécification.

C'est en fait exactement comme celà que je procédais quand je
programmais encore en C (et dans ma programmation C++
actuelle, les fichiers entêtes sont en fait entièrement
générés par Objecteering). Dans certains projets, même les
fichiers d'exemple de configuration et la documentation
utilisateur étaient générés à partir du source.



C'est plutôt faire des choses à l'inverse. Et ça ne marche que
sur des petits projets -- dans les grosses applications où j'ai
travaillé, ce n'était pas la même personne qui était responsable
des spécifications et des implémentations.

Une solution, évidemment (que ce soit du Java ou du C++), c'est
de définir les spécifications dans un langage de conception
(UML) ou de spécification de l'interface (Corba), et puis
générer les fichiers automatiquement.

Le gros avantage étant de concentrer en un seul endroit toutes
les informations sur une fonction.



Ce qui est précisement ce qu'on veut éviter.

Sans celà, quand on modifie l'interface d'une fonction il faut
toucher à trois fichiers (entête, source, documentation), ce
qui n'est jamais fait dans l'urgence et on se retrouve avec
des incohérences et des documentations pas à jour.



Quand on modifie l'interface d'une classe, il faut en général
toucher à des centaines de fichiers -- tous les clients. C'est
la raison principale pour les garder séparées ; pour ne pas les
modifier inopinement.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Wykaaa
James Kanze a écrit :
On Feb 17, 11:10 am, (Pascal J. Bourguignon)
wrote:



[snip]

C'est en fait exactement comme celà que je procédais quand je
programmais encore en C (et dans ma programmation C++
actuelle, les fichiers entêtes sont en fait entièrement
générés par Objecteering). Dans certains projets, même les
fichiers d'exemple de configuration et la documentation
utilisateur étaient générés à partir du source.



C'est plutôt faire des choses à l'inverse. Et ça ne marche que
sur des petits projets -- dans les grosses applications où j'ai
travaillé, ce n'était pas la même personne qui était responsable
des spécifications et des implémentations.

Une solution, évidemment (que ce soit du Java ou du C++), c'est
de définir les spécifications dans un langage de conception
(UML) ou de spécification de l'interface (Corba), et puis
générer les fichiers automatiquement.

Le gros avantage étant de concentrer en un seul endroit toutes
les informations sur une fonction.



Ce qui est précisement ce qu'on veut éviter.

Sans celà, quand on modifie l'interface d'une fonction il faut
toucher à trois fichiers (entête, source, documentation), ce
qui n'est jamais fait dans l'urgence et on se retrouve avec
des incohérences et des documentations pas à jour.



Quand on modifie l'interface d'une classe, il faut en général
toucher à des centaines de fichiers -- tous les clients. C'est
la raison principale pour les garder séparées ; pour ne pas les
modifier inopinement.



Bravo James.
Sur toutes ces questions, je suis à 100% d'accord avec toi !

Wykaaa
1 2