我需要扩展一个预处理器指令,例如:
拥有一个源文件和两个标头,我想只从一个特定标头展开一个define
,保留所有其他include
和define
。
主要思想是,给出与此类似的代码:
的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。运行它的最简单方法是扩展这些宏。我也欢迎其他方法来做到这一点。
答案 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 ,声明宏应该(不)展开。
我不清楚这是值得的。是的,如果您认为宏应该是非透明的,那么度量工具可能会在某些宏被大量使用的地方产生更准确的答案。如果你认为宏基本上只是一个看起来很滑稽的子程序,那么扩展这个宏就像内联函数体一样,你不会这样做来计算指标。