web-dev-qa-db-fra.com

Incompatibilité de compilation C vs C ++ - ne nomme pas un type

J'essaie d'utiliser la bibliothèque d'un fournisseur en combinaison avec mon application C++. La bibliothèque est largement basée sur C, ce qui ne pose normalement pas de problème avec le extern "C", mais j'ai rencontré un problème que le compilateur C++ n'accepte pas.

J'ai simplifié mon code dans les exemples de fichiers suivants. header.h représente un en-tête de la bibliothèque suppier, main.c/cpp sont mes propres fichiers. Ma vraie application est une application C++, je veux donc qu'elle fonctionne avec main.cpp.

header.h (notez la ligne u64 u64;):

#ifndef HEADER_H
#define HEADER_H

#include <stdint.h>

typedef uint64_t u64;

union teststruct {
    u64 u64;
    struct {
        u64 x:32;
        u64 y:32;
    } s;
};

#endif

principal c:

#include <stdio.h>
#include "header.h"

int main() {
    union teststruct a;
    a.u64=5;
    printf("%x\n", a.u64);

    return 0;
}

main.cpp (identique à main.c mais avec un extra extern "C" déclaration):

#include <stdio.h>

extern "C" {
#include "header.h"
}

int main() {
    union teststruct a;
    a.u64=5;
    printf("%x\n", a.u64);

    return 0;
}

Compiler main.c en utilisant la ligne

gcc -o test main.c

compile sans problèmes. Cependant, compiler la version C++ en utilisant le compilateur g ++ avec la commande

g++ -o test main.cpp

donne les erreurs de compilation suivantes:

In file included from main.cpp:12:0:
header.h:11:9: error: ‘u64’ does not name a type
         u64 x:32;
         ^
header.h:12:9: error: ‘u64’ does not name a type
         u64 y:32;
         ^

Le problème est que le fournisseur a utilisé le même nom (u64) pour le type et le nom de la variable, ce qui semble être une mauvaise idée pour commencer, mais gcc l'accepte apparemment. Je ne souhaite pas modifier la bibliothèque (c.-à-d. Header.h) car elle est très volumineuse, cela se produit souvent dans le code et des mises à jour me sont parfois fournies. Existe-t-il un moyen de faire accepter cette combinaison par g ++ ou de modifier main.cpp pour le compiler sans changer le fichier header.h?

51
Sander

teststruct définit une portée en C++. Vous pouvez former l'identifiant qualifié teststruct::u64. Donc, les règles de langue pour le compte de recherche de noms pour cela, permettant aux membres des classes et des unions de masquer les identificateurs dans l'étendue externe. Une fois que u64 u64; est introduit, le non qualifié u64 ne peut pas faire référence au global ::u64, seul le membre. Et le membre n'est pas un type.

En C union teststruct ne définit pas de portée. Le champ ne peut être utilisé que dans l'accès membre, il ne peut donc jamais y avoir de conflit. En tant que tel, le champ ne doit pas masquer l'identificateur de type d'étendue de fichier.

Autant que je sache, vous ne pouvez rien faire pour contourner facilement ce problème. Cette bibliothèque (qui est une bibliothèque C parfaitement valide) n'est pas une bibliothèque C++ valide. Pas différent de s'il utilisait new ou try comme noms de variables. Il faut l'adapter.

48
StoryTeller

Il semble que vous ayez un fichier d’en-tête illégal en C++, vous ne pouvez donc pas #include il en code compilé en C++. Si vous ne pouvez pas modifier le fichier d’en-tête de la bibliothèque (par exemple, en s’adressant à votre fournisseur de bibliothèque), l’option la plus simple consiste à écrire un wrapper compatible C++ fin autour de la bibliothèque:

Pour isoler votre code C++ par rapport à l'en-tête C, créez un fichier Wrapper.h et Wrapper.c, où le .h est valide pour l'inclusion en C++, pas inclut header.h, et fournit tous les types et fonctions nécessaires à l’interaction de la bibliothèque. Ensuite, dans le .c, vous pouvez #include "header.h" et implémentez tous les appels (et tout ce que vous devez faire pour convertir en toute sécurité entre les types). Cela devrait évidemment être compilé en C, pas en C++.

39
Max Langhof

Si votre incompatibilité mentionnée entre C et C++ est la seule, vous devriez pouvoir convertir header.h vers un fichier d’en-tête compatible C++ par programme, nommez-le comme suit: header.hpp. Et vous pouvez ensuite convertir les versions les plus récentes de la même manière.

Les erreurs du compilateur vous disent tout sur quoi et où doit être changé:

header.h:11:9: error: ‘u64’ does not name a type
  1. Ouvrir header.h;
  2. Recherchez la position 11: 9;
  3. Insérer :: Là;
  4. Répéter pour tous does not name a type Erreur.

Un certain traitement de chaîne et c'est fait.

PS: les convertisseurs C à C++ peuvent également le faire.

3