【问题标题】:Use #pragma pack with #define on Borland C++在 Borland C++ 上使用 #pragma pack 和 #define
【发布时间】:2015-06-20 05:17:44
【问题描述】:

我正在尝试使用 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,也不喜欢宏内部的预处理器指令,尽管它在 their website 上有所描述:

#define GETSTD #include <stdio.h>

我的问题是:有没有可能将此构造与 Borland 编译器一起使用来打包一个结构 没有 使用:

#pragma pack(1) 

打包每个结构?

有解决办法吗?

【问题讨论】:

  • 你仍然可以使用#include "packed_begin.h"#include "packed_end.h"(没有保护)
  • 感谢您的评论,但我不能在宏中使用#include,因为 borland 不支持。我可以重写库,但我希望有一个宏的可能性
  • @user2358582 它不应该,它不是合法的 C++。我相信 Jarod 的意思是您可以用它替换宏行。
  • 是的,我只是认为有可能不编辑库文件。我只是可以做 preg_replace,但是当库更新时,我必须再次这样做。有了宏,我就可以使用新文件,它仍然可以编译。

标签: c++ c++builder pragma borland-c++


【解决方案1】:

该标准为编写 pragma 提供了一种额外的替代方法:_Pragma 运算符:

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

如果 Borland 编译器支持它,它应该可以工作。

【讨论】:

  • 感谢您的回答,但不幸的是 Borland 编译器(我的版本)不支持 _Pragma。
  • @user2358582:C++Builder 的 32 位编译器没有,但它的 64 位和移动编译器可以。
【解决方案2】:

正如您所说,C++Builder 不支持宏内部的预处理器语句。这记录在 Embarcadero 的网站上:

#define (C++)

在每个单独的宏展开后,都会对新展开的文本进行进一步扫描。这允许嵌套宏的可能性:扩展文本可以包含可以替换的宏标识符。 但是,如果宏扩展为看起来像预处理指令的内容,则预处理器将无法识别该指令。

这是因为宏中的# 字符是为预处理器的字符串化操作符保留的。

包括 MSVC 在内的一些编译器通过 __pragma() 编译器扩展或 C99/C++x0 _Pragma() 扩展来绕过该限制。 C++Builder 的 Windows 32bit 编译器不支持其中任何一个。然而,它的 Windows 64bitmobile 编译器(均基于 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 编译器,你必须将逻辑移动到使用#pragma 的.h 文件中,然后你可以#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"

【讨论】:

  • 我只想补充一点,符合标准的 C++ 编译器不能 支持宏替换中的指令。 C++11 16.34./3:“生成的完全用宏替换的预处理标记序列即使类似于一个,也不会作为预处理指令处理,......”
猜你喜欢
  • 2016-01-15
  • 1970-01-01
  • 2014-05-10
  • 2016-04-28
  • 2016-01-30
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 2011-10-01
相关资源
最近更新 更多