【问题标题】:Fun with C macrosC 宏的乐趣
【发布时间】:2013-08-06 10:24:03
【问题描述】:

假设我在 C 中有一个名为 FOO 的函数宏。还有两个宏称​​为BAR1BAR2,它们基本上是同一个宏的两种风格。我想编写一个宏BAR,使其在函数中扩展为BAR1,在使用BAR 之前调用FOO,否则扩展为BAR2。比如:

void func1(void)
{
    FOO();
    ...
    BAR();
}

相当于

void func1(void)
{
    FOO();
    ...
    BAR1();
}

这个函数:

void func2(void)
{
    BAR();
}

相当于

void func2(void)
{
    BAR2();
}

我想避免在运行时引入全局变量或进行额外检查。这甚至可能吗?

【问题讨论】:

  • 如果BAR1BAR2 可以是绝对任意的宏,则不能,因为您不能动态地调整#define 的宏扩展。但是,如果您告诉我们BAR1BAR2 本质上是什么,那么可能有一种方法可以利用结构上的相似性来做到这一点。
  • 你准备好提交 IOCCC 了吗?
  • @nneonneo: FOO() 检查指针是否为 NULL。 BAR1() 取消引用该指针,而 BAR2() 没有。
  • @user2656304:我实际上相信编译器会对其进行优化。 NULL 检查非常便宜,大多数编译器可以在启用优化的情况下跳过多余的 NULL 检查。
  • @user2656304:不优雅?奇怪的词,因为你愿意以这种方式滥用预编译器。

标签: c macros


【解决方案1】:

简短回答:不。 C 预编译器对函数限制一无所知,因此即使您设法根据需要修改了 BAR 宏,也不会限制为当前函数。

现在,如果您愿意,可以在 BAR 宏中添加一些检查。并且可以编写这些检查以在编译时解决,因此不会产生运行时开销。

例如:

extern char _sentinel_[2];

#define FOO() char _sentinel_;

#define BAR() if (sizeof(_sentinel_) == 1) BAR1() else BAR2()

诀窍在于查找变量_sentinel_ 将解析全局变量或局部变量,具体取决于FOO() 的使用。由于if 中的条件是编译器常量,编译器会优化掉另一个分支。

【讨论】:

  • __FUNCTION__ 宏。
  • @user2656304:你打算用__FUNCTION__做什么? strcmp 它在预处理器中??
  • @user2656304: __FUNCTION__ 和 C99 中的 __func__ 是变量,而不是宏,IIRC。原因恰恰是预编译器对函数一无所知。出现混淆是因为 __FILE__ 和 __LINE__` 是宏,但预编译器确实知道文件和行...
  • 这意味着FOO必须用在函数的开头。中间的定义在 C99 之前是不合法的,块内的定义将无法按要求工作。
【解决方案2】:

我尝试使用gotos 的破解失败了,因为当不使用FOO() 时,BAR() 的跳转标签丢失。但是,不要害怕,我想出了一个更糟糕的破解方法。

您可以使用#includes 代替FOO()BAR() 的宏。这将允许您完全控制代码的扩展方式。

/* FOO file */
#define BAR_IS_BAR2
/* whatever code FOO needs to do */

/* BAR file */
#ifdef BAR_IS_BAR2
    BAR2();
    #undef BAR_IS_BAR2
#else
    BAR1();        
#endif

/*...in you source code...*/
void func1 () {
    #include "FOO"
    /*...*/
    #include "BAR"
}

void func2 () {
    #include "BAR"
}

【讨论】:

  • 天哪,我的眼睛。我认为 goto hack 很糟糕……这是 IOCCC 级别的糟糕。 (也许这是一种恭维。)
  • @nneonneo:它确实说“有趣的宏”,不是吗? :-)
  • +1。太糟糕了,你不能写#define BAR #include "BAR"。那将是最终的预编译器黑客。但可悲的是,如果有一个函数有 "FOO" 但没有 "BAR",这将失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-08
  • 1970-01-01
  • 1970-01-01
  • 2010-12-24
  • 2013-11-26
  • 2012-02-02
  • 2015-04-13
相关资源
最近更新 更多