Используйте #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 5

2 ответа:

Как вы уже сказали, C++Builder не поддерживает операторы препроцессора внутри макросов. Это задокументировано на сайте Embarcadero:

#определить (C++)

После каждого отдельного расширения макроса производится дальнейшее сканирование вновь развернутого текста. Это позволяет использовать вложенные макросы: развернутый текст может содержать идентификаторы макросов, которые подлежат замене. однако, если макрос расширяется в то, что выглядит как предварительная обработка директива, директива не будет распознана препроцессором.

Причина этого заключается в том, что символ # внутри макроса зарезервирован для оператора строкования препроцессора.

Некоторые компиляторы, включая 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"

Стандарт предлагает одну дополнительную альтернативу для написания прагм: оператор _Pragma:

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

Если компилятор Borland поддерживает его, он должен работать.