【问题标题】:C Programming: Preprocessor, macros as tokensC 编程:预处理器,宏作为标记
【发布时间】:2010-12-18 13:39:51
【问题描述】:

我正在尝试做一些在概念上与此类似的事情,但似乎无法让它发挥作用(最后显示错误)任何想法?

#include <stdio.h>

int main( int argc , char const *argv[] )
{
  int abc_def_ghi = 42;
  #define SUFFIX ghi
  #define VAR(prefix) prefix##_def_##SUFFIX
  printf( "%d\n" , VAR(abc) );
  return 0;
}

// untitled:8: error: ‘abc_def_SUFFIX’ undeclared (first use in this function)

【问题讨论】:

  • const argv?我第一次看到这样的事情!这个想法看起来不错,但我不确定我是否喜欢它:它使main 不符合标准并阻止我做我从未做过的事情;)
  • 这不是不合格的。 argv 可以声明为等同于 char* argv[] (C99 5.1.2.2.1),并且添加 const 不会改变任何东西,除了 main() 允许使用它(没有演员表) .请记住,指向非 const 的指针可以转换为指向 const 的指针,这没有问题 - 直到这些指针的值比较相等(6.3.2.3/2)。
  • 好的,谢谢迈克尔。反过来(删除const)会使其不符合要求。我开始喜欢它了!
  • 嗨,抱歉打扰了,我应该把它拿出来的。使用 TextMate 时,键入 main 后跟 tab 会为 main 方法填充一个脚手架,这就是它的一部分。

标签: c macros token c-preprocessor stringification


【解决方案1】:

这适用于足够的间接级别。虽然另一个答案就足够了,但我想提供这段代码作为演示:

#define SUFFIX ghi

#define VAR1(prefix) prefix##_def_##SUFFIX
VAR1(abc)

#define VAR2_(prefix, sfx) prefix##_def_##sfx
#define VAR2(prefix) VAR2_(prefix,SUFFIX)
VAR2(abc)

#define VAR3_(prefix, sfx) prefix##_def_##sfx
#define VAR3x(prefix,sfx) VAR3_(prefix,sfx)
#define VAR3(prefix) VAR3x(prefix,SUFFIX)
VAR3(abc)

保存这是一个文本文件,x.c,并且只对其进行预处理。

gcc -E x.c

观察和思考。我自己也不太明白。只需花两个小时尝试使用 stringify 来获取宏即可工作。有趣的是,有时需要双重间接。

【讨论】:

  • 我得到 abc_def_SUFFIX abc_def_SUFFIX abc_def_ghi 根据史蒂夫的解释,这听起来与宏替换的顺序有关。
【解决方案2】:

正确使用字符串化 (#) 或标记粘贴 (##) 预处理运算符的常用习惯是使用第二级间接。 (What are the applications of the ## preprocessor operator and gotchas to consider?)。

#define STRINGIFY2( x) #x
#define STRINGIFY(x) STRINGIFY2(x)

#define PASTE2( a, b) a##b
#define PASTE( a, b) PASTE2( a, b)

然后:

int main( int argc , char const *argv[] )
{
  int abc_def_ghi = 42;
  #define SUFFIX ghi
  #define VAR(prefix) PASTE( prefix, PASTE( _def_, SUFFIX))
  printf( "%d\n" , VAR(abc) );
  return 0;
}

应该会给你想要的结果。

基本上,### 运算符的处理发生在宏替换之前。然后发生另一轮宏替换。因此,如果您希望将宏与这些操作一起使用,您必须使用简单地进行替换的第一级 - 否则首先发生字符串化或粘贴,并且宏不再是宏 - 它们是第一轮字符串化/粘贴产生。

说得更直接一点——第一级宏允许宏参数被替换,然后第二级宏替换进行stringify/token-pasing操作。

【讨论】:

  • 哇,谢谢,STRINGIFY 还解决了我遇到的另一个问题。
【解决方案3】:

你只需要额外的间接:

#include <stdio.h>

int main( int argc , char const *argv[] )
{
  int abc_def_ghi = 42;
  #define SUFFIX ghi
  #define VAR3(prefix, suffix) prefix##_def_##suffix
  #define VAR2(prefix, suffix) VAR3(prefix, suffix)
  #define VAR(prefix) VAR2(prefix, SUFFIX)
  printf( "%d\n" , VAR(abc) );
  return 0;
}

虽然看起来是多余的,但其实不然。

【讨论】:

  • 现在尝试理解6.10.3.3 The ## operator 的标准语对我来说有点太晚了,但它解释了为什么在那里。 (pdf@open-std.org/JTC1/sc22/wg14/www/docs/n1401.pdf)
  • 因为宏的替换列表在其参数被替换并应用# 和## 运算符之前,它本身并不受宏替换的影响。因此,在提问者的代码中,def_##SUFFIX 被替换为 def_SUFFIX,然后才有机会将 SUFFIX 替换为 ghi。在caf的代码中,当suffix在VAR2中被SUFFIX替换时,参数首先进行宏扩展(6.10.3.1/1)。结果是VAR3(abc,ghi),产生abc_def_ghi。请注意,VAR3(abc,SUFFIX) 仍然会给出 abc_def_SUFFIX,因为 ## 后面的参数没有展开(也是 6.10.2.1/1)。
  • "(also 6.10.2.1/1)" - 我的意思是“(also 6.10.3.1/1)”。
猜你喜欢
  • 2014-04-17
  • 2020-02-09
  • 2013-07-16
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 2019-11-29
相关资源
最近更新 更多