【问题标题】:Any options for C preprocessor to only expand special macros? [closed]C 预处理器的任何选项只能扩展特殊宏? [关闭]
【发布时间】:2013-12-02 01:28:45
【问题描述】:

对于源代码级别的分析,我需要扩展除#include之外的宏,可以吗?

比如在下面的sn-p中,我只希望assert扩展为__assert_fail,而不是包括assert.h和扩展assert

#include <assert.h>

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

【问题讨论】:

  • 你为什么要这么做?
  • 既然assert的定义在assert.h中,你建议如何扩展assert而不包括assert.h?
  • @shf301:这就是他的要求。
  • 我想他是说他只想要包含在应用程序中的内容。编译器和链接器已经这样做了,对吧?
  • Ow - 所以你想要的是部分扩展。这听起来像stackoverflow.com/questions/6482321/…

标签: c macros c-preprocessor


【解决方案1】:

如果您使用 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&lt;void&gt; (xyz) : __assert_fail ("xyz", "&lt;file_name&gt;", 5, __PRETTY_FUNCTION__));

【讨论】:

    【解决方案2】:

    您必须编写自己的预处理器。如果您遵循将包含放在顶部的简单规则(大多数人都会这样做),那应该不会太难。

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

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

    如果您不遵循“包含在顶部的规则”,那只会稍微困难一些。您可以在每个包含指令(或每组连续的包含指令)之前和之后插入标记行,以跟踪哪些指令位于哪些标记之间。

    【讨论】:

      猜你喜欢
      • 2018-01-04
      • 2020-10-18
      • 1970-01-01
      • 1970-01-01
      • 2020-09-18
      • 1970-01-01
      • 1970-01-01
      • 2014-04-17
      相关资源
      最近更新 更多