问题
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?
回答1:
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"
回答2:
The standard offers one extra alternative for writing pragmas: the _Pragma
operator:
#define PACKED_BEGIN _Pragma("pack(push, 1)")
#define PACKED
#define PACKED_END _Pragma("pack(pop)")
If the Borland compiler supports it, it should work.
来源:https://stackoverflow.com/questions/29630011/use-pragma-pack-with-define-on-borland-c