如何通过删除部分或全部#include

时间:2018-12-04 18:12:37

标签: c++ c c-preprocessor

头文件中发生了很多预处理魔术。我想在源文件中查看这种魔术的结果,但其中没有所有的#include内容。

例如,当我在运行预处理器时

#include<stdio.h>    
#define astring "hello world"                         
int main()                
{                           
    printf("%s\n",astring); 
    return 0;
} 

我得到27k行输出。在这种情况下,我只希望最后7行左右。

有时候我想要某些include指令的结果,而另一些(几乎总是像系统标头一样)我想忽略的结果。

我很少会在不寻常的位置添加指令,这些指令我也希望省略或保留输出。

有没有什么工具/方法可以帮助我?

编辑:目标是不获取可编译的代码。在我的情况下,预处理器会在功能上更改源代码(例如,使用预处理器在c中实现类似模板的功能),并且查看后处理的源代码对于调试很有用。我正在通过gcc / g ++使用gnu cpreprocessor,据我所知,它正在调用cpp。

2 个答案:

答案 0 :(得分:1)

我想到了这个,只是和gcc -Eawk一起玩。我注意到,gcc -E在进入其他文件时会输出格式为# <linenum> "<filename>" <other stuff>的行。所以基本上,如果我可以跟踪该文件名,则可以打印出我关心的行。

我不擅长awk,因此可能会有一种更有效的方法。

gcc -E example.c | awk '
/^#/ { filename = $3 }
!/^#/ {
    if (filename == "\"example.c\"")
        print $0
}'

如果该行以#开头,则存储文件名。否则,如果文件名是我关心的文件名,请打印出该行。将example.c替换为您的文件名。

对于您的示例,输出:

int main()
{
    printf("%s\n","hello world");
    return 0;
}

我不确定它是否100%正确(例如,我不知道是否可以有其他以#开头的行)。您可以尝试使用它来获得想要的东西。

答案 1 :(得分:1)

一个可能的简单解决方案是在您关心扩展的程序文本周围插入开始和结束标记。虽然您不能使用注释插入标记,但是可以使用#pragma指令(至少使用普通的C编译器)达到相同的效果。

根据标准(第6.10.6节),编译指示可以被实现识别,然后具有实现定义的行为(可能导致编译失败),或者被实现不识别,在这种情况下它被忽略。由于必须通过符合标准的实现来记录实现定义的行为,因此,从理论上讲,应该可以确定实现可以识别哪些杂物,然后可以使用与该模式不匹配的任何东西。实际上,它很少那么简单,但是通常“ #pragma”之后的第一个标记将标识编译器或子系统,因此gcc识别的大多数编译指示将以标记GCC开始。 (不过,有很多传统的用法。)

所以您可能需要尝试一下,但至少要在我刚开始使用的编译器上进行测试

#pragma X_PPTRACE 0

#pragma X_PPTRACE 1

只是被预处理器传递了(尽管-Wall启用了警告),允许使用非常简单的awk程序:

gcc -Wall -Wno-unknown-pragmas -E ... |
awk '/#pragma[[:space:]]+X_PPTRACE/{trace=$3;}trace'