C预处理器的任何选项只能扩展特殊的宏?

时间:2013-12-02 01:28:45

标签: c macros c-preprocessor

对于源级别分析,我需要扩展除#include之外的宏,是否可能?

例如,在以下代码段中,我只希望将assert扩展为__assert_fail,而不是包含assert.h并展开assert

#include <assert.h>

int main(void) {
  assert(0); // expand this
  return 0;
}

2 个答案:

答案 0 :(得分:5)

如果您正在使用gcc,则使用-E作为开关,只需在文件上运行预处理器。这将扩展文件中找到的所有宏,但保持源的其余部分不变。此外,您可以使用-U统一在源中展开的任何宏。请参阅GCC preprocessor

所以,在这:

#include <assert.h>

int main(int argc, char * argv[])
{
  assert(0);
  return 0;
}

调用:

g++ -E assert_test.cpp -o assert_test.ii

返回assert_test.ii:

# 1 "assert_test.cpp"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 30 "/usr/include/stdc-predef.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4
# 31 "/usr/include/stdc-predef.h" 2 3 4
# 1 "<command-line>" 2
# 1 "assert_test.cpp"
# 1 "/usr/include/assert.h" 1 3 4
# 36 "/usr/include/assert.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 371 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4
# 385 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 386 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 372 "/usr/include/features.h" 2 3 4
# 395 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 1 3 4
# 10 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4
# 396 "/usr/include/features.h" 2 3 4
# 37 "/usr/include/assert.h" 2 3 4
# 67 "/usr/include/assert.h" 3 4
extern "C" {


extern void __assert_fail (const char *__assertion, const char *__file,
      unsigned int __line, const char *__function)
     throw () __attribute__ ((__noreturn__));


extern void __assert_perror_fail (int __errnum, const char *__file,
      unsigned int __line, const char *__function)
     throw () __attribute__ ((__noreturn__));




extern void __assert (const char *__assertion, const char *__file, int __line)
     throw () __attribute__ ((__noreturn__));


}
# 2 "assert_test.cpp" 2

int main(int argc, char * argv[])
{
  ((0) ? static_cast<void> (0) : __assert_fail ("0", "assert_test.cpp", 5, __PRETTY_FUNCTION__));
  return 0;
}

所以,至少在我的系统上:

assert(0);

扩展为以下内容:

((0) ? static_cast<void> (0) : __assert_fail ("0", "assert_test.cpp", 5, __PRETTY_FUNCTION__));

其中__assert_fail是外部定义的函数(通常包含libc);因此,要回答您的问题,您可以使用自己喜欢的文本替换(sed / awk / perl)实用程序并将assert(xyz);扩展为((xyz) ? static_cast<void> (xyz) : __assert_fail ("xyz", "<file_name>", 5, __PRETTY_FUNCTION__));

答案 1 :(得分:1)

您必须编写自己的预处理器。如果你按照简单的规则(大多数人这样做)将你的包括在顶部,那就不应该太难了。

  • 逐行读取源文件,并找出最后一个include指令的位置。
  • 创建一个完全重复的临时文件,除了使用额外的标记行来标识include指令的结束位置以及其余代码的开始位置。
  • 通过C预处理器发送该临时文件。
  • 在预处理文件中找到标记行,并使用原始文件中包含的include指令创建一个替换之前所有内容的新文件。

事实上,在使用操作系统附带的命令行工具的shell脚本中,这一切都应该很容易。

如果你不遵循“包含在最高规则”,那将只会有点困难。您可以在每个include指令(或每组连续的include指令)之前和之后插入标记行,跟踪哪些指令在哪些标记之间。