Search code examples
c++c++builderpragmaborland-c++

Use #pragma pack with #define on Borland C++


I am trying to pack some structs with Borland C++Builder (XE6) (in the future: bcc).

I am using a library which uses the following construct to create structs:

#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

The bcc compiler does not like the MSC __pragma, and does not like preprocessor directives inside of macros although it is described on their website:

#define GETSTD #include <stdio.h>

My Question is: Is there any possibility to use this construct with the Borland Compiler for packing a struct without using:

#pragma pack(1) 

to pack every struct?

Are there any workarounds for this?


Solution

  • As you stated, C++Builder does not support preprocessor statements inside of macros. This is documented on Embarcadero's site:

    #define (C++)

    After each individual macro expansion, a further scan is made of the newly expanded text. This allows for the possibility of nested macros: The expanded text can contain macro identifiers that are subject to replacement. However, if the macro expands into what looks like a preprocessing directive, the directive will not be recognized by the preprocessor.

    The reason for that is because the # character inside of a macro is reserved for the preprocessor's stringizing operator.

    Some compilers, including MSVC, get around that restriction with the __pragma() compiler extension, or the C99/C++x0 _Pragma() extension. C++Builder's Windows 32bit compiler does not support either of those. However, its Windows 64bit and mobile compilers (which are all based on clang and support C++11) DO support both of them. So you can add support for those compilers in the macros like this:

    #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
    

    If you want to support the C++Builder Windows 32bit compiler, you will have to move the logic into .h files that use #pragma for it, and then you can #include those files where needed (at least until the compiler is updated to support clang/C++11 - which Embarcadero is currently working on):

    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
    

    Then you can do this:

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

    If you take this approach, you can just drop PACKED_BEGIN/PACKED_END altogether:

    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"