Forum Programmation.c De l'usage des #include

Posté par  .
Étiquettes : aucune
0
8
fév.
2005
Bonjour,

Je suis entrain de coder une application, mais je me r ends compte (non sans désarroi !), que les premières lignes de mes ".c" sont rapidement envahies par des "#include" à tout va.
Que ce soient des inclusions de bibilothèques standard (string, socket, stdio et consorts) à mes modules persos ("configuration.h", "network.h", ...etc), ça devient assez "lourd" (surtout pour la maintenance).

Comment font les grandes applications ? Il y a t il un .h qui fait lui-meme appel à tous les headers nécerssaires à l'appli ?

Est-ce mal de mettre des #include à tout va dans les .h eux-meme ?
  • # #include <foo.h> /* foo(), bar(), BAZ */

    Posté par  (site web personnel) . Évalué à 3.

    A mon avis, mettre les #include dans le .h qui sera lui même #includé dans le .c ne changera rien au problème de la maintenance. Personnellement ce que je fais c'est que j'ajoute les #includes une fois que j'ai terminé d'écrire le code et je commente chaque #include en disant ce dont j'ai besoin dans le .h que j'utilise. Genre:
    #include <stdlib.h> /* malloc(3), free(3), EXIT_*, NULL */
    Si tu commences à avoir vraiment beaucoup d'#includes dans un seul fichier c'est peut-être parce que tu essais de faire trop de choses qui n'ont rien à voir dans le même fichier.

    pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

    • [^] # Re: #include <foo.h> /* foo(), bar(), BAZ */

      Posté par  (site web personnel) . Évalué à 3.

      Et aussi je regroupe les #includes par origine:
      /* ISO C99 */
      #include <string.h> /* memset(3), strlen(3), NULL */
      #include <stdlib.h> /* malloc(3) */
      #include <stdbool.h> /* bool, true, false */

      /* SUSv2 */
      #include <inttypes.h> /* uint16_t */
      #include <netdb.h> /* gethostbyname(3) */
      #include <sys/socket.h> /* socket(2), AF_INET, send(2), sockaddr,... */
      #include <arpa/inet.h> /* htons(3) */
      #include <sys/types.h> /* size_t */

      /* others */
      #include "foobar.h" /* quux(), toto() */

      pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

      • [^] # Re: #include <foo.h> /* foo(), bar(), BAZ */

        Posté par  . Évalué à 1.

        Hum, sympa le coup de mettre en commentaires les appels système et/ou fonctions de des libs utlisés.

        Je vais faire ça compléter d'un script que je mettra dans le répertoire de mon projet pour vérifier que le .h est bel et bien nécessaire (à coup de grep/sed).

        Merci pour ces infos.
        • [^] # Re: #include <foo.h> /* foo(), bar(), BAZ */

          Posté par  (site web personnel) . Évalué à 2.

          Pas bête le coup du script, je crois que je vais faire pareil.

          pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

        • [^] # Le script

          Posté par  . Évalué à 0.

          Voici le script, même si c'est un peu "goret" :


          #!/bin/bash
          #
          # check_headers.sh - Check that the headers are mandatory in your C sources.
          #
          # Conventions :
          # #include <stdlib.h> /* NULL */
          # #include <stdio.h> /* fread(), fwrite() */
          #
          # Then, it will check that functions fread() and fwrite(), and macro NULL
          # are indeed used in the current source file.
          # Note that functions/macros are separated using a comma.
          #
          # Author : Jean-Romain "Lockness" PAC <L0ckness@yahoo.fr>
          # Date : February, 8th, 2005
          # License : GPLv2 (see http://www.gnu.org/copyleft/gpl.html(...) for more details)
          #

          usage()
          {
          echo "Usage: $0 FILE"
          exit 1
          }

          if [ $# != 1 ]
          then
          usage
          fi

          if [ ! -f "$1" ]
          then
          echo "$0: unable to open \"$1\""
          exit 1
          fi

          LIST_HEADERS=$(grep "#include[\ ]*[<|\"].*\.h[>|\"].*" "$1")
          NB_LINES=$(echo "$LIST_HEADERS" | wc -l)

          TOKENS=""
          for NUMLINE in `seq $NB_LINES`
          do
          LINE=$(echo "$LIST_HEADERS" | head -$NUMLINE | tail -1)
          LINETOKENS="$LINE"

          # Removing left side
          LINETOKENS="$(echo "$LINETOKENS" | sed 's/.*\/\*[ ]*//g')"

          # Removing right side
          LINETOKENS=`echo "$LINETOKENS" | sed 's/[ ]*\*\/.*//g'`

          # Removing blank spaces
          LINETOKENS=`echo "$LINETOKENS" | sed 's/[ ]*//g'`

          # Removing left bracket (not to have pb with arguments after for matching)
          LINETOKENS=`echo "$LINETOKENS" | sed 's/(//g'`

          # Removing right bracket (not to have pb with arguments after for matching)
          LINETOKENS=`echo "$LINETOKENS" | sed 's/)//g'`

          NEWTOKENS=$(echo "$LINETOKENS" | tr "," "\n")
          TOKENS=$(echo -e "$TOKENS\n$NEWTOKENS")
          done


          for SEARCHED_TOKEN in `echo "$TOKENS"`
          do
          NB_EVENTS=$(grep "$SEARCHED_TOKEN" "$1" | wc -l)

          # Sure that there is a least one token (this of the include line)
          if [ ! $NB_EVENTS -gt 1 ]
          then
          echo "Token [$SEARCHED_TOKEN] not found in the file."
          fi
          done

          exit 0


          Si on teste sur ce fichier :

          #include <stdio.h> /* fread(), fwrite() */
          #include <stdlib.h> /* NULL */
          #include <lib_pas_necessaire.h> /* MACRO_PAS_UTILISEE */

          int main(void)
          {
          int a=5;
          int *b = NULL;

          fread(bidon);

          return (0);
          }


          On obtient :

          lockness@enzo:~/labo/include $ ./check_headers.sh source.c
          Token [fwrite] not found in the file.
          Token [MACRO_PAS_UTILISEE] not found in the file.


          Donc ça marche plutôt bien :)

          Si vous voulez améliorer le script (notamment pour dire si un include est complètement inutile (vérifier qu'aucun des tokens n'est présent dans le fichier)), libre à vous !
          • [^] # En Perl

            Posté par  (site web personnel) . Évalué à 2.

            Je l'ai refait en Perl, ça manque un peu de fini (j'ai fait ça en qq minuets sur le temps de midi) mais a priori ça marche bien et ça marche aussi pour les trucs genre documentés avec le numéro de section de la page de man. Genre pour free(3) il va bien chercher "free(" dans le code (contrairement à ton script).

            http://krunch.servebeer.com/~krunch/vrac/sw/qua/checkheaders.pl(...)

            (bon en fait c'est totalement illisible et dans 2h je saurai même plus comment j'ai fait ça)

            pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

  • # C'est normal

    Posté par  . Évalué à 3.

    Il n'y a rien de mal à faire ce que tu fais.
    Par convention, tous les include sont proprement rassemblés au tout début des fichiers de code source : ainsi, ça reste très "propre". Et c'est pareil dans tous les langages !
  • # .h Vs .c

    Posté par  (site web personnel) . Évalué à 4.

    Evites de mettre trop de #include dans tes .h : Ca rajoute des dépendances inutiles aux fichiers qui incluent ce .h (=> risques de dépendances croisées ch..., nombre de fichiers a recompiler quand tu modifie un .h, ...)

    Par contre, il faut en mettre assez. Une bonne convention est d'avoir un X.c par X.h dont la première ligne est #include "X.h", ce qui te permet d'être sur que ton X.h est auto-sufisant.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.