Используйте #pragma pack с #define на Borland C++
Я пытаюсь упаковать некоторые структуры с Borland C++Builder (XE6) (в будущем: bcc).
Я использую библиотеку, которая использует следующую конструкцию для создания структур:
#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
Компилятор bcc не любит MSC __pragma
и не любит директивы препроцессора внутри макросов, хотя это описано на их веб-сайте :
#define GETSTD #include <stdio.h>
Мой вопрос: есть ли возможность использовать эту конструкцию с компилятором Borland для упаковки структуры Без используя:
#pragma pack(1)
Чтобы упаковать каждую структуру?
Существуют ли обходные пути для этого?
2 ответа:
Как вы уже сказали, C++Builder не поддерживает операторы препроцессора внутри макросов. Это задокументировано на сайте Embarcadero:
После каждого отдельного расширения макроса производится дальнейшее сканирование вновь развернутого текста. Это позволяет использовать вложенные макросы: развернутый текст может содержать идентификаторы макросов, которые подлежат замене. однако, если макрос расширяется в то, что выглядит как предварительная обработка директива, директива не будет распознана препроцессором.
Причина этого заключается в том, что символ
Некоторые компиляторы, включая MSVC, обходят это ограничение с помощью расширения компилятора#
внутри макроса зарезервирован для оператора строкования препроцессора.__pragma()
или расширения C99/C++x0_Pragma()
. Компилятор C++Builder Windows 32bit не поддерживает ни то, ни другое. Однако его Windows 64bit имобильные компиляторы (которые все основаны на clang и поддерживают C++11) делают поддержку обоих из них. Таким образом, вы можете добавить поддержку этих компиляторов в макросы следующим образом:#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
Если вы хотите поддерживать компилятор C++Builder Windows 32bit , вам придется переместить логику в.h файлы, которые используют
#pragma
для него, а затем вы можете#include
те файлы, где это необходимо (по крайней мере, до тех пор, пока компилятор не будет обновлен для поддержки clang/C++11 - который Embarcadero в настоящее время работа над):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
Тогда вы можете сделать следующее:
#include "pack1_begin.h" PACKED_BEGIN struct PACKED { short someSampleShort; char sampleByte; int sampleInteger; } structType_t; PACKED_END #include "pack_end.h"
Если вы примете этот подход, вы можете просто отбросить
PACKED_BEGIN
/PACKED_END
всего: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"