web-dev-qa-db-fra.com

Pourquoi mes gardes de compilation n'empêchent-ils pas les inclusions à définitions multiples?

J'ai un fichier d'en-tête x.h qui est inclus dans plus d'un fichier source * .c. Ce fichier d'en-tête a défini certaines variables de structure.

J'ai placé un garde de prévention d'inclusion multiple au début du fichier d'en-tête en tant que:

#ifndef X_H
#define X_H
...
..
//header file declarations and definitons.


#endif//X_H

Sur la construction, j'obtiens des erreurs de l'éditeur de liens liées à plusieurs définitions. Je comprends le problème.

  1. Une protection contre les inclusions multiples en haut du fichier d'en-tête, comme je l'ai fait, n'empêchera-t-elle pas les inclusions multiples du fichier d'en-tête x.h et évitera ainsi les définitions multiples des variables présentes dans x.h?

  2. #pragma une fois ne fonctionne pas sur ce compilateur particulier, alors quelle est la solution? Quelqu'un avait posté this réponse à une question similaire. Cela ne semble pas fonctionner pour moi. Comment fonctionne cette solution?

43
goldenmean

Si l'éditeur de liens se plaint, cela signifie que vous avez des définitions plutôt que de simples déclarations dans votre en-tête. Voici un exemple de choses qui ne seraient pas correctes.

#ifndef X_H
#define X_H

int myFunc()
{
  return 42; // Wrong! definition in header.
}

int myVar; // Wrong! definition in header.

#endif

Vous devez diviser cela en fichier source et en-tête comme ceci:

Entête:

#ifndef X_H
#define X_H

extern int myFunc();

extern int myVar; 

#endif

C Source:

int myFunc()
{
  return 42; 
}

int myVar; 
54
Roddy

L'utilisation des gardes d'inclusion empêche une unité de compilation d'inclure l'en-tête deux fois. Par exemple. si l'en-tête B.h inclut A.h et B.cpp inclut A.h et B.h, tout ce qui provient de A.h serait déclaré deux fois dans la compilation B.cpp si vous n'utilisiez pas les gardes d'inclusion.

Vos gardes incluent empêcher que cela se produise, tout va bien jusqu'à présent.

Mais vous obtenez plusieurs définitions au moment du lien, c'est-à-dire que deux unités de compilation définissent la même chose, cela signifie probablement que vous avez une vraie définition dans votre en-tête, utilisez extern pour toutes les variables, assurez-vous que les fonctions sont soit en ligne soit définies dans le fichier cpp.

13
Pieter

Les protections d'en-tête ne sont valables que pour une seule unité de compilation, c'est-à-dire le fichier source. S'il vous arrive d'inclure un fichier d'en-tête plusieurs fois, peut-être parce que tous les en-têtes inclus à partir de main.c comprend à son tour stdio.h alors les gardes vous aideront.

Si vous avez la définition d'une fonction f dans x.h qui est inclus par main.c et util.c, alors c'est comme copier et coller la définition de f dans main.c lors de la création main.o et faire de même pour util.c créer util.o. Ensuite, l'éditeur de liens se plaindra et cela se produit malgré vos gardes d'en-tête. Avoir plusieurs #include "x.h" instructions dans main.c est bien sûr possible grâce à ces gardes.

12
perreal

Si les fonctions ne sont pas importantes, vous pouvez utiliser "inline" avant elles et l'éditeur de liens ne se plaindra pas.

7
nclement

L'utilisation d'un garde d'inclusion multiple empêche les erreurs compilateur, mais vous obtenez une erreur de l'éditeur de liens. Avez-vous des définitions de données dans le fichier d'en-tête qui n'utilisent pas extern?

2
Greg Hewgill

Peut être X_H est déjà défini ailleurs? Je viens de rencontrer ce problème, où Xlib définit X_H dans /usr/include/X11/X.h.

Pour vérifier, vous pouvez appeler gcc -dM -E (si vous utilisez gcc), par exemple dans le système de build que j'utilise et qui fonctionne avec CC=gcc CFLAGS="-dM -E" make. Si le fichier de sortie contient #define X_H même si vous le supprimez de votre fichier (utilisez Y_H par exemple), alors il est déjà défini en dehors de votre code source.

0
Michael