扩展单个C预处理器指令

时间:2013-12-16 13:01:21

标签: c-preprocessor code-metrics

我需要扩展一个预处理器指令,例如: 拥有一个源文件和两个标头,我想只从一个特定标头展开一个define,保留所有其他includedefine

主要思想是,给出与此类似的代码:

的defs.h:

#define FOO(X,op) int X(int a,int b) { return a op b; }

other_file.h:

#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4
#define FIVE 5

main.c中:

"file: main.c "
#include <stdio.h>
#include "defs.h"
#include "other_file.h"
FOO(add,+)
FOO(sub,-)
FOO(mul,*)
FOO(div,/)

int main()

{

  printf("%d\n",add(ONE,TWO));
  printf("%d\n",sub(THREE,FOUR));
  printf("%d\n",mul(FIVE,FIVE));
  printf("%d\n",div(25,FIVE));
  return 0;
}

我将main.c输出与相同的包含,但FOO扩展到创建的功能。我知道这个例子很傻,但我打算在更大的代码数据库上运行它。

这样做的动机是在宏中定义的函数中运行cccc。运行它的最简单方法是扩展这些宏。我也欢迎其他方法来做到这一点。

2 个答案:

答案 0 :(得分:1)

您可以使用GCC的-E-nostdinc-nostdinc++-fpreprocessed参数。

对于您的示例,您可以运行:

gcc -E -nostdinc -fpreprocessed main.c

输出结果为:

# 1 "main.c"
#include <stdio.h>
#include "defs.h"
#include "other_file.h"
FOO(add,+)
FOO(sub,-)
FOO(mul,*)
FOO(div,/)

int main()

{
  printf("%d\n",add(ONE,TWO));
  printf("%d\n",sub(THREE,FOUR));
  printf("%d\n",mul(FIVE,FIVE));
  printf("%d\n",div(25,FIVE));
  return 0;
}

如果标题不是那么复杂,就像在您的示例中一样,您可以强制gcc预处理整个文件,即使有一些丢失的宏也是如此。 E.g:

cp other_file.h other_file.h_orig
echo "" > other_file.h
gcc -E -nostdinc main.c

输出:

# 1 "main.c"
# 1 "<command-line>"
# 1 "main.c"
main.c:1:19: error: no include path in which to search for stdio.h
 #include <stdio.h>
                   ^

# 1 "defs.h" 1
# 3 "main.c" 2
# 1 "other_file.h" 1
# 4 "main.c" 2
int add(int a,int b) { return a + b; }
int sub(int a,int b) { return a - b; }
int mul(int a,int b) { return a * b; }
int div(int a,int b) { return a / b; }

int main()

{
  printf("%d\n",add(ONE,TWO));
  printf("%d\n",sub(THREE,FOUR));
  printf("%d\n",mul(FIVE,FIVE));
  printf("%d\n",div(25,FIVE));
  return 0;
}

它会删除标题包含,但是...会在std标题上打印出错误,而不是stdout。

这适用于您的小示例,但在较大的代码库中,您可能会遇到一些问题......

以下是手册(GCC 4.8.2)中参数的简要概述:

  

-E :在预处理阶段后停止;不要正确运行编译器。输出采用预处理源代码的形式   被发送到标准输出。

     

-fpreprocessed :向预处理器指示输入文件已经过预处理。这会抑制像宏这样的东西   扩展,三元组转换,转义换行拼接,以及   处理大多数指令。

     

-nostdinc :不要在标准系统目录中搜索头文件。只有您使用-I选项指定的目录。

     

-nostdinc ++ :不要在特定于C ++的标准目录中搜索头文件,但仍然搜索其他标准   目录。

答案 1 :(得分:-1)

我们的DMS Software Reengineering Toolkit及其C Front End会执行此操作。

DMS提供通用程序解析/分析基础结构。 C前端以此为基础,提供全功能C前端,配有C预处理器。

通常,DMS C预处理器的行为与标准预处理器类似:它预处理所有内容,生成替代的令牌流。不同寻常的是,它可以配置为不处理条件(这是全有或全无),或仅扩展指定的宏。特别是,它接受一个自定义 #pragma ,声明宏应该(不)展开。

我不清楚这是值得的。是的,如果您认为宏应该是非透明的,那么度量工具可能会在某些宏被大量使用的地方产生更准确的答案。如果你认为宏基本上只是一个看起来很滑稽的子程序,那么扩展这个宏就像内联函数体一样,你不会这样做来计算指标。