2015-04-14 4 views
5

J'essaye d'emballer certaines structures avec Borland C++ Builder (XE6) (dans le futur: bcc).Utilisez #pragma pack aveC#define sur Borland C++

J'utilise une bibliothèque qui utilise la construction suivante pour créer struct:

#ifdef _MSC_VER 
    #define PACKED_BEGIN __pragma(pack(push, 1)) 
    #define PACKED 
    #define PACKED_END __pragma(pack(pop)) 
#elif defined(__GNUC__) 
    #define PACKED_BEGIN 
    #define PACKED __attribute__((__packed__)) 
    #define PACKED_END 
#endif 


PACKED_BEGIN 
struct PACKED { 
    short someSampleShort; 
    char sampleByte; 
    int sampleInteger; 
} structType_t; 
PACKED_END 

Le compilateur Cci n'aime pas le MSC __pragma, et n'aime pas les directives de préprocesseur à l'intérieur des macros bien qu'elle soit décrite sur their website :

#define GETSTD #include <stdio.h> 

Ma question est: est-il possible d'utiliser cette construction avec le compilateur Borland pour emballer un struct sans en utilisant:

#pragma pack(1) 

d'emballer chaque struct?

Existe-t-il des solutions de contournement pour cela?

+3

Vous peut toujours utiliser '#include" packed_begin.h "' et '#include" pa cked_end.h "' (sans gardes) – Jarod42

+0

Merci pour votre commentaire, mais je ne peux pas utiliser #include dans une macro parce que borland ne supporte pas cela. Je pourrais réécrire la bibliothèque, mais j'espérais une possibilité avec des macros – user2358582

+1

@ user2358582 Et bien, il ne devrait pas, ce n'est pas légal C++. Je crois que Jarod voulait que vous puissiez * remplacer * les lignes de macro avec ça. – Angew

Répondre

2

Comme vous l'avez indiqué, C++ Builder ne prend pas en charge les instructions de préprocesseur dans les macros. Ceci est documenté sur le site de Embarcadero:

#define (C++)

Après chaque extension macro individuelle, une autre analyse est faite du texte nouvellement agrandi. Cela permet la possibilité de macros imbriquées: Le texte développé peut contenir des identifiants de macro qui peuvent être remplacés. Cependant, si la macro se développe dans ce qui ressemble à une directive de prétraitement, la directive ne sera pas reconnue par le préprocesseur.

La raison est parce que le caractère # à l'intérieur d'une macro est réservé pour opérateur de stringizing du préprocesseur.

Certains compilateurs, y compris MSVC, contournent cette restriction avec l'extension de compilateur __pragma() ou l'extension C99/C++ x0 _Pragma(). Le compilateur Windows 32 bits de de C++ Builder ne prend en charge ni l'un ni l'autre. Cependant, ses Windows 64bit et compilateurs mobiles (qui sont tous basés sur clang et le soutien C++ 11) DO tous les deux. Ainsi, vous pouvez ajouter le support pour les compilateurs dans les macros comme celui-ci:

#if defined(__BORLANDC__) 
    #if defined(__clang__) 
     #define PACKED_BEGIN __pragma(pack(push, 1)) 
     #define PACKED 
     #define PACKED_END __pragma(pack(pop)) 
    #else 
     #error Cannot define PACKED macros for this compiler 
    #endif 
#elif defined(_MSC_VER) 
    #define PACKED_BEGIN __pragma(pack(push, 1)) 
    #define PACKED 
    #define PACKED_END __pragma(pack(pop)) 
#elif defined(__GNUC__) 
    #define PACKED_BEGIN 
    #define PACKED __attribute__((__packed__)) 
    #define PACKED_END 
#else 
    #error PACKED macros are not defined for this compiler 
#endif 

Si vous souhaitez soutenir le C++ Builder de Windows 32 bits compilateur, vous devrez déplacer la logique dans.fichiers qui utilisent h #pragma pour elle, et vous pouvez #include ces fichiers si nécessaire (au moins jusqu'à ce que le compilateur est mis à jour pour supporter clang/C++ 11 - qui Embarcadero travaille actuellement):

pack1_begin.h:

#if defined(__BORLANDC__) 
    #define PACKED_BEGIN 
    #define PACKED 
    #define PACKED_END 
    #pragma pack(push, 1) 
#elif defined(_MSC_VER) 
    #define PACKED_BEGIN __pragma(pack(push, 1)) 
    #define PACKED 
    #define PACKED_END __pragma(pack(pop)) 
#elif defined(__GNUC__) 
    #define PACKED_BEGIN 
    #define PACKED __attribute__((__packed__)) 
    #define PACKED_END 
#else 
    #error PACKED macros are not defined for this compiler 
#endif 

pack_end.h:

#if defined(__BORLANDC__) 
    #pragma pack(pop) 
#endif 

Ensuite, vous pouvez faire ceci:

#include "pack1_begin.h" 
PACKED_BEGIN 
struct PACKED { 
    short someSampleShort; 
    char sampleByte; 
    int sampleInteger; 
} structType_t; 
PACKED_END 
#include "pack_end.h" 

Si vous adoptez cette approche, vous pouvez simplement déposer PACKED_BEGIN/PACKED_END au total:

pack1_begin.h:

#if defined(__BORLANDC__) || defined(_MSC_VER) 
    #define PACKED 
    #pragma pack(push, 1) 
#elif defined(__GNUC__) 
    #define PACKED __attribute__((__packed__)) 
#else 
    #error PACKED macro is not defined for this compiler 
#endif 

pack_end.h:

#if defined(__BORLANDC__) || defined(_MSC_VER) 
    #pragma pack(pop) 
#endif 

#include "pack1_begin.h" 
struct PACKED { 
    short someSampleShort; 
    char sampleByte; 
    int sampleInteger; 
} structType_t; 
#include "pack_end.h" 
+0

J'ajouterais simplement qu'un compilateur C++ conforme * ne peut pas * supporter les directives dans le remplacement de macro. C++ 11 16.34./3: "La séquence de jetons de prétraitement qui a été complètement remplacée par macro n'a pas été traitée comme une directive de pré-traitement même si elle ressemble à une ..." – Angew

0

La norme offre une solution supplémentaire pour pragma écrit: l'opérateur _Pragma:

#define PACKED_BEGIN _Pragma("pack(push, 1)") 
#define PACKED 
#define PACKED_END _Pragma("pack(pop)") 

Si le compilateur Borland prend en charge, il devrait fonctionner.

+0

Merci pour votre réponse, mais malheureusement le compilateur Borland (ma version) ne supporte pas _Pragma. – user2358582

+1

@ user2358582: le compilateur 32 bits de C++ Builder ne le fait pas, mais ses compilateurs 64 bits et mobiles le font. –