L'utilité des #include ?
Résolu/Fermé
Neoflash146
Messages postés
16
Date d'inscription
vendredi 28 septembre 2012
Statut
Membre
Dernière intervention
26 janvier 2014
-
24 août 2013 à 16:11
Neoflash146 Messages postés 16 Date d'inscription vendredi 28 septembre 2012 Statut Membre Dernière intervention 26 janvier 2014 - 26 août 2013 à 10:32
Neoflash146 Messages postés 16 Date d'inscription vendredi 28 septembre 2012 Statut Membre Dernière intervention 26 janvier 2014 - 26 août 2013 à 10:32
A voir également:
- L'utilité des #include ?
- Processeur utilité - Guide
- Google drive utilité - Guide
- Glary utilite - Télécharger - Nettoyage
- Java utilité ✓ - Forum Java
- Quelle est l'utilité de cortana ? - Guide
4 réponses
mamiemando
Messages postés
33077
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
18 avril 2024
7 749
25 août 2013 à 00:44
25 août 2013 à 00:44
Pour faire simple, une fonction en C, pour être utilisable, doit normalement être au préalable déclarée, ce qui signifie que l'on connaît son prototype. Même si ton compilateur peut tolérer des déclarations implicites, c'est clairement déconseillé car ça conduit à des programmes illisibles et aux dépendances incompréhensibles. On va donc supposer que ne pas respecter cette règle est une erreur de programmation.
À quoi sert #include ?
Est-ce qu'un #include est pour autant nécessaire ? Considérons ce programme :
On pourrait tout à fait écrire ceci, ça compile sans aucun warning :
... car finalement, du fichier stdio.h, seule la ligne en italique que j'ai reportée nous intéresse. Pour autant, le code de la fonction printf n'est pas reporté dans mon fichier ".c". Seul le prototype est intéressant à ce stade, car l'implémentation de la fonction "printf" sera donc "retrouvée" au moment de linker. Cet exemple semble montrer que #include n'est finalement pas si indispensable et a plutôt un intérêt d'ordre pratique.
En effet, si on travaille dans un seul fichier, on pourrait copier coller les prototypes de toutes les fonctions dont on a besoin en début de ce fichier et ça marcherait très bien, du moment qu'on récupère l'implémentation de ces fonctions à la fin de la compilation (plus précisément au linkage). Et c'est finalement ce que j'ai fait dans l'exemple ci-dessus.
Quel est l'intérêt de #include ?
Mais déjà à ce stade on comprend que ça ne serait clairement pas pratique. Supposons qu'on travaille sur plusieurs fichiers, cela signifierait qu'en plus on devrait faire ces copier-coller potentiellement dans chacun de ces fichiers ! Je passe sur les considérations de définitions multiples pour ne pas compliquer le propos, mais ce serait également un point qui justifie l'intérêt des #include et des headers.
Supposons qu'on développe la libc. On a codé des fonctions relatives aux strings, d'autres aux entrées sorties etc. On a envie de les mettre facilement à disposition des gens qui vont développer en utilisant la libc. On va donc rassembler ces fonctions par "thèmes", par exemple les fonctions relatives aux chaînes de caractères dans un même header (string.h). Dans l'absolu, ce développeur utilisant ces fonctions aura besoin de "copier coller" leur déclaration. Il pourra le faire facilement en important ce header.
Comment savoir quels #include faire ?
On perçoit donc qu'il suffit qu'un fichier .c inclue tous les .h permettant de rassembler les déclarations de fonctions implémentées à l'extérieur de ce .h pour résoudre la plupart des problèmes. Donc par exemple si j'utilise la fonction "strdup", déclarée dans <string.h>, il suffit que j'inclue <string.h>. On peut imaginer que ce même programme inclue un autre header, mettons "toto.h" qui lui même inclue <string.h>. Mais comme finalement l'implémentation de "toto.h" peut potentiellement évoluer, en toute rigueur, je dois explicitement inclure <string.h> et "toto.h".
La seule question au final, c'est dans quel header une fonction est déclarée. Si tu es sous linux tu peux facilement retrouver cette information avec le man avec la commande suivante :
http://fr.wikipedia.org/wiki/Man_(Unix)
Note que tu peux aussi taper ça dans google (en particulier si tu es sous windows), tu tomberas par exemple sur :
http://manpagesfr.free.fr/man/man3/printf.3.html
On voit donc ici que printf est fourni par <stdio.h>
Comment marche et que fait #include ?
Attachons-nous maintenant à la manière dont c'est réalisé en C. Ce "copier-coller", s'il devait avoir lieu, se ferait au moment où le développeur écrit son code, donc avant la compilation. On sent donc que ce traitement doit être effectué avant la compilation. C'est exactement ce qui est fait en pratique. Toutes les lignes qui commencent par un # sont traitées par le pré-compilateur. En outre, toutes les lignes effectuant un #include déclenche un copier coller.
https://forums.commentcamarche.net/forum/affich-37604426-la-compilation-et-les-modules-en-c-et-en-c#les-phases-de-compilation
Ensuite la compilation a proprement parler peut avoir lieu. En général on écrit des fichiers C en général en vue de produire à terme un exécutable ou une librairie (que je vais appeler binaire). Chaque fichier ".c" produit un fichier ".o", et l'ensemble de ces fichiers ".o" et les librairies tierces sont "rassemblées" pour produire le binaire final (étape de linkage). Si toutes les déclarations implicites de fonctions sont levées au linkage, le binaire compile après quelque warning. Si au contraire un symbole (par exemple une déclaration de fonction) n'est pas trouvé (ou en plusieurs examplaires) alors l'étape de linkage échoue. C'est l'un des intérêts supplémentaires des #include headers : ceux-ci sont généralement conçus pour qu'il n'y ait pas de risque de définitions multiples à l'aide de verrous (voir #ifndef, #define, #endif) au moment du linkage.
Bonne chance
À quoi sert #include ?
Est-ce qu'un #include est pour autant nécessaire ? Considérons ce programme :
#include <stdio.h> int main() { printf("coucou"); return 0; }
On pourrait tout à fait écrire ceci, ça compile sans aucun warning :
extern int printf (const char *__restrict __format, ...); int main() { printf("coucou"); return 0; }
... car finalement, du fichier stdio.h, seule la ligne en italique que j'ai reportée nous intéresse. Pour autant, le code de la fonction printf n'est pas reporté dans mon fichier ".c". Seul le prototype est intéressant à ce stade, car l'implémentation de la fonction "printf" sera donc "retrouvée" au moment de linker. Cet exemple semble montrer que #include n'est finalement pas si indispensable et a plutôt un intérêt d'ordre pratique.
En effet, si on travaille dans un seul fichier, on pourrait copier coller les prototypes de toutes les fonctions dont on a besoin en début de ce fichier et ça marcherait très bien, du moment qu'on récupère l'implémentation de ces fonctions à la fin de la compilation (plus précisément au linkage). Et c'est finalement ce que j'ai fait dans l'exemple ci-dessus.
Quel est l'intérêt de #include ?
Mais déjà à ce stade on comprend que ça ne serait clairement pas pratique. Supposons qu'on travaille sur plusieurs fichiers, cela signifierait qu'en plus on devrait faire ces copier-coller potentiellement dans chacun de ces fichiers ! Je passe sur les considérations de définitions multiples pour ne pas compliquer le propos, mais ce serait également un point qui justifie l'intérêt des #include et des headers.
Supposons qu'on développe la libc. On a codé des fonctions relatives aux strings, d'autres aux entrées sorties etc. On a envie de les mettre facilement à disposition des gens qui vont développer en utilisant la libc. On va donc rassembler ces fonctions par "thèmes", par exemple les fonctions relatives aux chaînes de caractères dans un même header (string.h). Dans l'absolu, ce développeur utilisant ces fonctions aura besoin de "copier coller" leur déclaration. Il pourra le faire facilement en important ce header.
Comment savoir quels #include faire ?
On perçoit donc qu'il suffit qu'un fichier .c inclue tous les .h permettant de rassembler les déclarations de fonctions implémentées à l'extérieur de ce .h pour résoudre la plupart des problèmes. Donc par exemple si j'utilise la fonction "strdup", déclarée dans <string.h>, il suffit que j'inclue <string.h>. On peut imaginer que ce même programme inclue un autre header, mettons "toto.h" qui lui même inclue <string.h>. Mais comme finalement l'implémentation de "toto.h" peut potentiellement évoluer, en toute rigueur, je dois explicitement inclure <string.h> et "toto.h".
La seule question au final, c'est dans quel header une fonction est déclarée. Si tu es sous linux tu peux facilement retrouver cette information avec le man avec la commande suivante :
http://fr.wikipedia.org/wiki/Man_(Unix)
man 3 printf
Note que tu peux aussi taper ça dans google (en particulier si tu es sous windows), tu tomberas par exemple sur :
http://manpagesfr.free.fr/man/man3/printf.3.html
On voit donc ici que printf est fourni par <stdio.h>
Comment marche et que fait #include ?
Attachons-nous maintenant à la manière dont c'est réalisé en C. Ce "copier-coller", s'il devait avoir lieu, se ferait au moment où le développeur écrit son code, donc avant la compilation. On sent donc que ce traitement doit être effectué avant la compilation. C'est exactement ce qui est fait en pratique. Toutes les lignes qui commencent par un # sont traitées par le pré-compilateur. En outre, toutes les lignes effectuant un #include déclenche un copier coller.
https://forums.commentcamarche.net/forum/affich-37604426-la-compilation-et-les-modules-en-c-et-en-c#les-phases-de-compilation
Ensuite la compilation a proprement parler peut avoir lieu. En général on écrit des fichiers C en général en vue de produire à terme un exécutable ou une librairie (que je vais appeler binaire). Chaque fichier ".c" produit un fichier ".o", et l'ensemble de ces fichiers ".o" et les librairies tierces sont "rassemblées" pour produire le binaire final (étape de linkage). Si toutes les déclarations implicites de fonctions sont levées au linkage, le binaire compile après quelque warning. Si au contraire un symbole (par exemple une déclaration de fonction) n'est pas trouvé (ou en plusieurs examplaires) alors l'étape de linkage échoue. C'est l'un des intérêts supplémentaires des #include headers : ceux-ci sont généralement conçus pour qu'il n'y ait pas de risque de définitions multiples à l'aide de verrous (voir #ifndef, #define, #endif) au moment du linkage.
Bonne chance
tj anh
Messages postés
18
Date d'inscription
dimanche 11 août 2013
Statut
Membre
Dernière intervention
24 août 2013
24 août 2013 à 16:37
24 août 2013 à 16:37
quelles foncs ???
je pense vous avez utilisez les foncs qui ne sont pas de string.h
je pense vous avez utilisez les foncs qui ne sont pas de string.h
fiddy
Messages postés
11069
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
23 avril 2022
1 835
Modifié par fiddy le 24/08/2013 à 16:46
Modifié par fiddy le 24/08/2013 à 16:46
Bonjour,
Ce n'est pas anormal puisque le code des fonctions de string.h sont contenues dans la bibliothèque standard, linkée automatiquement lors de la compilation. Alors à quoi sert string.h ? Elle contient, entres autres, les prototypes des fonctions *str*. Du coup, cela permet de meilleurs contrôles lors de la compilation. Si tu ne le mets pas, cela doit te générer un avertissement (sauf si ton compilateur est trop permissif...). Bref, il faut inclure le header si tu utilises ses fonctions.
Google is your friend
Ce n'est pas anormal puisque le code des fonctions de string.h sont contenues dans la bibliothèque standard, linkée automatiquement lors de la compilation. Alors à quoi sert string.h ? Elle contient, entres autres, les prototypes des fonctions *str*. Du coup, cela permet de meilleurs contrôles lors de la compilation. Si tu ne le mets pas, cela doit te générer un avertissement (sauf si ton compilateur est trop permissif...). Bref, il faut inclure le header si tu utilises ses fonctions.
Google is your friend
Neoflash146
Messages postés
16
Date d'inscription
vendredi 28 septembre 2012
Statut
Membre
Dernière intervention
26 janvier 2014
24 août 2013 à 16:49
24 août 2013 à 16:49
C'est ça que je ne comprend pas, pourquoi les fonctions (comme strstr et printf) fonctionnaient toujours même quand je n'incluais aucun header ?
fiddy
Messages postés
11069
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
23 avril 2022
1 835
Modifié par fiddy le 24/08/2013 à 16:58
Modifié par fiddy le 24/08/2013 à 16:58
Je viens de te le dire...
Relis mon post.
Relis mon post.
Neoflash146
Messages postés
16
Date d'inscription
vendredi 28 septembre 2012
Statut
Membre
Dernière intervention
26 janvier 2014
24 août 2013 à 17:28
24 août 2013 à 17:28
"Bref, il faut inclure le header si tu utilises ses fonctions."
Je n'inclus pas le header.
J'utilise ses fonctions.
Le compilateur ne me met pas d'avertissement (j'utilise GNU GCC Compiler avec Code::Blocks)
Le programme fonctionne.
Quid ?
Je n'inclus pas le header.
J'utilise ses fonctions.
Le compilateur ne me met pas d'avertissement (j'utilise GNU GCC Compiler avec Code::Blocks)
Le programme fonctionne.
Quid ?
fiddy
Messages postés
11069
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
23 avril 2022
1 835
24 août 2013 à 17:49
24 août 2013 à 17:49
C'est pas la conclusion qu'il faut lire, mais ce qu'il y a au dessus.
Alors, je remets ici le passage qui répond à ta question.
Ce n'est pas anormal puisque le code des fonctions de string.h sont contenues dans la bibliothèque standard, linkée automatiquement lors de la compilation. Alors à quoi sert string.h ? Elle contient, entres autres, les prototypes des fonctions *str*. Du coup, cela permet de meilleurs contrôles lors de la compilation. Si tu ne le mets pas, cela doit te générer un avertissement (sauf si ton compilateur est trop permissif...).
Donc, si tu n'as pas d'avertissements, cela veut dire que ton compilateur est trop permissif, mal configuré...
Par exemple, as-tu -Wall comme flag ?
Alors, je remets ici le passage qui répond à ta question.
Ce n'est pas anormal puisque le code des fonctions de string.h sont contenues dans la bibliothèque standard, linkée automatiquement lors de la compilation. Alors à quoi sert string.h ? Elle contient, entres autres, les prototypes des fonctions *str*. Du coup, cela permet de meilleurs contrôles lors de la compilation. Si tu ne le mets pas, cela doit te générer un avertissement (sauf si ton compilateur est trop permissif...).
Donc, si tu n'as pas d'avertissements, cela veut dire que ton compilateur est trop permissif, mal configuré...
Par exemple, as-tu -Wall comme flag ?
Neoflash146
Messages postés
16
Date d'inscription
vendredi 28 septembre 2012
Statut
Membre
Dernière intervention
26 janvier 2014
24 août 2013 à 19:17
24 août 2013 à 19:17
Heu...Je sais pas...C'est quoi un flag ?
fiddy
Messages postés
11069
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
23 avril 2022
1 835
Modifié par fiddy le 25/08/2013 à 00:16
Modifié par fiddy le 25/08/2013 à 00:16
Ce sont les options lancées au moment de la compilation.
Par défaut, le compilateur est trop permissif (il ne respecte même pas, me semble-t-il, stricto sensu, le standard par défaut). Il faut donc aller dans les options de Code::Blocks pour paramétrer correctement le compilateur et lui faire afficher les avertissements.
Par défaut, le compilateur est trop permissif (il ne respecte même pas, me semble-t-il, stricto sensu, le standard par défaut). Il faut donc aller dans les options de Code::Blocks pour paramétrer correctement le compilateur et lui faire afficher les avertissements.
25 août 2013 à 00:49
25 août 2013 à 00:51
25 août 2013 à 12:02
Je remercie aussi fiddy qui m'a dit que je devais mettre Wall dans les flag. D'ailleurs au début je croyais que c'était "mur" alors que c'était "Warning all", juste pour le dire.
25 août 2013 à 22:47
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Chacune de ces options permet de désactiver des messages de warnings. Le mot clé "all" permet de toutes les activer d'un coup.
Bonne chance
25 août 2013 à 22:57
Chacune de ces options permet de désactiver des messages de warnings. Le mot clé "all" permet de toutes les activer d'un coup.
-Wall est loin de tous les activer.
Par exemple, pour bien faire, il faudrait rajouter -Wextra, -Wunreachable-code, -Wunreachable-code et j'en passe des dizaines...