6
votes

Duplication de la définition du préprocesseur

J'ai deux bibliothèques et malheureusement elles définissent deux définitions de préprocesseur identiques (que je dois utiliser):

lib1.h

#include <Lib1.h>
#include <lib2.h>
...
int myint = MYINT;

lib2.h p >

#define MYINT 2

Dans mon programme, je dois utiliser les deux:

#define MYINT 1

Et ici, j'ai une erreur que MYINT ne peut pas être résolu .

Comment puis-je résoudre ce problème lorsque je ne peux pas modifier les fichiers lib?


6 commentaires

Vous n'avez pas indiqué ce que vous voulez que MYINT soit finalement à ce stade, vous pouvez #ifdef MYINT #undef MYINT etc.


Le préprocesseur va remplacer la macro par la valeur, laquelle doit-il choisir?


De quelle version de la macro avez-vous besoin?


Avez-vous le luxe de cibler un seul système d'exploitation? Si oui, lequel? Je pense en termes de liaison dynamique des bibliothèques.


@Bathsheba: Comment la liaison dynamique résoudrait-elle les collisions dans les identificateurs de préprocesseur?


@EricPostpischil: L'intention serait d'abstraire tous les conflits de dénomination de la bibliothèque consommatrice. Bien sûr, nous ne pouvons pas en dire trop sans plus de détails qui manquent.


4 Réponses :


3
votes

Obtenez la valeur MYINT de la première bibliothèque avant que la seconde ne la remplace.

#include <Lib1.h>
int myInt1 = MYINT;
#undef MYINT
#include <lib2.h>
int myInt2 = MYINT;
#undef MYINT

Bien sûr, cela ne fonctionne pas si MYINT est quelque chose de dynamique et vous devez conserver son contenu actuel.

Modifié par handy999: pas de point-virgule à la fin des instructions du préprocesseur.


4 commentaires

J'ajouterais #undef MYINT après chaque pour éviter les avertissements et les abus


Bonne suggestion, je l'ai ajoutée à la réponse.


Les deux bibliothèques ont déjà été identifiées comme ayant un conflit de nom. Les inclure dans une seule unité de traduction me semble très optimiste.


Vous avez raison. Le problème fondamental est que deux bibliothèques utilisent des noms de macro qui ne sont pas assez spécifiques pour ne pas créer un conflit de noms comme celui-ci. Idéalement, j'essaierais d'aborder la partie «impossible de modifier la lib».



5
votes

Vous pouvez #undef MYINT avant d'inclure l'en-tête comme solution de contournement.

#undef MYINT
#include <Lib1.h>
const int myint_lib1 = MYINT; // 1

#undef MYINT
#include <lib2.h>
const int myint_lib2 = MYINT; // 2


2 commentaires

Utilisez constexpr si possible.


BTW, le premier #undef n'est pas requis.



0
votes

Sans astuces de préprocesseur:

lib1_handler.h

#include "lib1_handler.h"
#include "lib2_handler.h"

int void () {
  return lib1_handler_myint || lib2_handler_myint_f();
}

lib1_handler.c

#include <Lib2.h>

int lib2_handler_myint = MYINT;
// or
int lib2_handler_myint_f() { return MYINT; }

lib2_handler.h

extern int lib2_handler_myint;
// or
int lib1_handler_myint_f();

lib2_handler.c

#include <Lib1.h>

int lib1_handler_myint = MYINT;
// or
int lib1_handler_myint_f() { return MYINT; }

extern int lib1_handler_myint;
// or
int lib1_handler_myint_f();


0 commentaires

0
votes

L'approche que je prendrais est de dériver de chacun des fichiers d'inclusion une version étendue des fichiers d'inclusion qui fourniront le MYINT via un mécanisme différent en dehors des fichiers d'inclusion eux-mêmes.

Créez donc un fichier d'inclusion à partir de lib1.h nommé lib1_ext.h contenant les lignes suivantes:

int funcStuff (int a, struct b *pBthing);

#define FUNCSTUFF (pBthing)  funcStuff(MYINT, (pBthing))

et de même pour lib2.h créez lib2_ext.h comme dans:

#if !defined(MYLIB2_EXT_H_INCLUDED)
#define MYLIB2_EXT_H_INCLUDED
// ensure that MYINT is not defined no matter what order the include files are used
#undef MYINT
#include "lib2.h"
const int myInt_lib2 = MYINT;  // make a copy of the value of MYINT if it is needed
// make sure MYINT is undefined to allow the compiler to catch any dependencies on it
#undef MYINT
#endif

maintenant lorsque vous utilisez l'une des fonctionnalités de la bibliothèque utiliser la copie respective de la valeur MYINT , myInt_lib1 lors de l'utilisation de la fonctionnalité lib1.h et / ou de myInt_lib2 lors de l'utilisation de lib2.h . Cependant, si MYINT est uniquement utilisé avec le fichier d'en-tête de la bibliothèque lui-même et n'est pas nécessaire nulle part pour utiliser réellement la bibliothèque, vous pouvez simplement ignorer cette déclaration.

Voir aussi Puis-je redéfinir une macro C ++ puis la redéfinir? qui montre comment enregistrer et restaurer une définition de macro avec les compilateurs de certains fournisseurs et la directive pragma . Cependant, cela ne semble pas vraiment applicable avec votre publication.

Cette publication a également une réponse qui décrit les bases de l'expansion des macros et pourquoi le const int myInt_lib1 = MYINT; code > est nécessaire pour enregistrer la valeur de MYINT plutôt que d'utiliser le préprocesseur comme dans #define MYINT_LIB1 MYINT pour enregistrer la valeur de MYINT . Le préprocesseur retarde le développement d'une macro aussi longtemps que possible et le résultat est que d'essayer d'utiliser une macro de préprocesseur comme dans #define MYINT_LIB1 MYINT pour enregistrer la valeur de MYINT ne ne fonctionne pas une fois que MYINT n'est pas défini à l'aide de la directive #undef . Lorsque le préprocesseur remplace d'abord le texte MYINT_LIB1 par le texte MYINT puis effectue une nouvelle analyse, puisque MYINT est désormais indéfini, le texte MYINT reste et le résultat est une erreur de compilation si vous êtes chanceux.

Une chose à considérer avec ce travail autour de

Ce travail autour suppose que tout ce qui est nécessaire est la valeur numérique de MYINT qui est traitée comme une valeur constante int . Donc, il suppose que les endroits où MYINT est utilisé sont des endroits où un const int peut également être utilisé.

Cela signifie que tout type de collage de jetons , le test #if ou toute autre action du préprocesseur qui implique de traiter le texte défini par MYINT comme du texte pouvant être utilisé par le préprocesseur pour d'autres opérations de macro ne fonctionnera pas correctement en dehors des endroits où les lib.h ou lib2.h sont inclus et traités par le préprocesseur.

Cela signifie également que vous ne pouvez pas spécifier une option du compilateur pour déclarer MYINT dans le cadre de la compilation conditionnelle puisque la macro créée par l'option du compilateur va être ignorée et éliminée par cette solution.

Donc, toute dépendance qui la source générée par le préprocesseur a sur MYINT car une macro de texte en dehors de chacun des fichiers d'inclusion provoquera la rupture de la compilation.

Un exemple de dépendance possible serait un macro dans lib1.h qui utilise MYINT pour créer un argument supplémentaire, invisible à une fonction comme dans:

#if !defined(MYLIB1_EXT_H_INCLUDED)
#define MYLIB1_EXT_H_INCLUDED
// ensure that MYINT is not defined no matter what order the include files are used
#undef MYINT
#include "lib1.h"
const int myInt_lib1 = MYINT;  // make a copy of the value of MYINT if it is needed
// make sure MYINT is undefined to allow the compiler to catch any dependencies on it
#undef MYINT
#endif

avec l'attente que toute personne utilisant la bibliothèque utiliserait FUNCSTUFF (& bThing); plutôt que funcStuff (MYINT, & bThing); . Pour faire ce travail, vous devez soit utiliser la fonction funcStuff () directement comme dans funcStuff (myInt_lib1, & bThing); soit créer votre propre version de FUNCSTUFF () macro qui utilise myInt_lib1 plutôt que MYINT.


0 commentaires