定义宏中的编译指示

Posted

技术标签:

【中文标题】定义宏中的编译指示【英文标题】:Pragma in define macro 【发布时间】:2011-03-03 02:05:13 【问题描述】:

有没有办法在宏中嵌入 pragma 语句和其他语句?

我正在尝试实现以下目标:

#define DEFINE_DELETE_OBJECT(type)                      \
    void delete_ ## type_(int handle);                  \
    void delete_ ## type(int handle);                                                \
    #pragma weak delete_ ## type_ = delete_ ## type

如果存在提升解决方案(除了 wave),我可以接受。

【问题讨论】:

可以说两者都不是 - #pragmas 不是由 C 或 C++ 标准定义的。 预处理器是,即使他想要运行的特定允许子命令不是。 @DeadMG:C 和 C++ 之间有很多共同点。虽然预处理大部分很常见,但根据所使用的语言标准(C89、C99、C++ 和 C++0x FCD),如何指定预处理存在重大差异。 @James McNellis:仅仅因为从技术上讲,大多数 C 程序都可以移植到 C++ 中,因此并没有真正实现通用功能,因为绝大多数 C++ 程序员都不会这样做。这两种语言实际上并没有太多共同点。 【参考方案1】:

如果您使用的是 c99 或 c++0x,则有 pragma 运算符,用作

_Pragma("argument")

相当于

#pragma argument

除了它可以在宏中使用(参见 c99 标准的第 6.10.9 节,或 c++0x 最终委员会草案的第 16.9 节)

例如,

#define STRINGIFY(a) #a
#define DEFINE_DELETE_OBJECT(type)                      \
    void delete_ ## type ## _(int handle);                  \
    void delete_ ## type(int handle);                   \
    _Pragma( STRINGIFY( weak delete_ ## type ## _ = delete_ ## type) )
DEFINE_DELETE_OBJECT(foo);

当放入gcc -E 时会给出

void delete_foo_(int handle); void delete_foo(int handle);
#pragma weak delete_foo_ = delete_foo
 ;

【讨论】:

仅供参考:MSVC 具有 __pragma() 预处理器运算符,不幸的是,它与 C99 的 _Pragma() 运算符略有不同(C99 采用字符串文字,MSVC 采用不在字符串中的标记) :msdn.microsoft.com/en-us/library/d9x1s805.aspx @MichaelBurr MSVC 总是必须与众不同,不是吗?【参考方案2】:

您可以使用 _Pragma("argument") 做的一件好事是使用它来处理一些编译器问题,例如

#ifdef _MSC_VER
#define DUMMY_PRAGMA _Pragma("argument")
#else
#define DUMMY_PRAGMA _Pragma("alt argument")
#endif

【讨论】:

【参考方案3】:

不,没有便携的方法可以做到这一点。再说一次,根本没有可移植的方式来使用#pragma。正因为如此,许多 C/C++ 编译器定义了自己的方法来执行类似 pragma 的事情,并且它们通常可以嵌入到宏中,但是每个编译器都需要不同的宏定义。如果你愿意走这条路,你通常会做这样的事情:

#if defined(COMPILER_GCC)
#define Weak_b
#define Weak_e __attribute__((weak))
#elif defined(COMPILER_FOO)
#define Weak_b __Is_Weak
#define Weak_e
#endif

#define DEFINE_DELETE_OBJECT(type)                      \
    Weak_b void delete_ ## type_(int handle) Weak_e;    \
    Weak_b void delete_ ## type(int handle)  Weak_e;    

如果您想将 Weak_bWeak_e 定义为开头和结尾的括号结构并不明显,因为一些编译器(如 GCC)将属性作为附录添加到类型签名中,而另一些编译器(如 MSC)添加它作为前缀(或者至少它做过一次,自从我使用 MSC 已经有好几年了)。即使您必须将整个类型签名传递给编译器构造,使用括号结构也可以定义始终有效的东西。

当然,如果您尝试将其移植到没有您想要的属性的编译器,那么您无能为力,只能将宏扩展为空,并希望您的代码仍然可以运行。在纯粹的警告或优化编译指示的情况下,这很可能。在其他情况下,没有那么多。

哦,我怀疑您实际上需要将 Weak_b 和 Weak_e 定义为带参数的宏,但我不愿意通读文档以了解如何仅为此示例创建弱定义。我把它留给读者作为练习。

【讨论】:

【参考方案4】:

有没有办法在宏中嵌入 pragma 语句和其他语句?

不,您不能将预处理器语句放入预处理器语句中。但是,您可以将其放入 inline 函数中。不过,这会破坏C 标签。

【讨论】:

将它放入内联函数有什么好处?预处理器指令在任何可以识别函数的东西之前被处理。 C99 有 inline,大多数主要的 C89 实现都有一些变化。 @Chris 假设你的评论是针对我的 - 你的意思是 - 什么? @Neil - 不,抱歉。我把它指向@sbi 的最后一句话。 @Chris:啊,所以inline 是 C 从 C++ 借来的另一个东西! :)

以上是关于定义宏中的编译指示的主要内容,如果未能解决你的问题,请参考以下文章

如何用C中#define宏中的字符串常量替换函数名

使用宏中的 NSDictionary 对象创建 NSArray

可变参数宏中的参数计数无效

探索scala宏中的表达式树

如何在过程宏中提供有用的编译器错误?

Confluence 6 在你用户宏中使用参数