如何显示“预处理”代码忽略包括GCC

问题描述 投票:1回答:5

我想知道是否可以用gcc输出'preprocessed'代码,但'忽略'(不扩展)包括:

ES我得到了这个主要内容:

#include <stdio.h>
#define prn(s) printf("this is a macro for printing a string: %s\n", s);

int int(){
char str[5] = "test"; 
prn(str);
return 0;
}

我跑gcc -E main -o out.c

我有:

/*
all stdio stuff
*/

int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

我只想输出:

#include <stdio.h>
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

或者,至少,只是

int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

PS:如果可能扩大“本地”""包括而不是扩大“全球”<>包括将是伟大的

c linux gcc c-preprocessor
5个回答
2
投票

我同意Matteo Italia的评论,如果你只是阻止#include指令被扩展,那么结果代码将不代表编译器实际看到的内容,因此它在故障排除中的用途有限。

这是一个解决这个问题的想法。在包含之前和之后添加变量声明。任何相当独特的变量都可以。

int begin_includes_tag;
#include <stdio.h>
... other includes
int end_includes_tag;

然后你可以这样做:

> gcc -E main -o out.c | sed '/begin_includes_tag/,/end_includes_tag/d'

sed命令将删除这些变量声明之间的所有内容。


2
投票

当cpp扩展包含时,它会添加# directives (linemarkers)以追溯到原始文件的错误。

你可以添加一个后期处理步骤(它可以用任何脚本语言编写,如果你愿意,也可以用C语言编写),只需解析行标记并过滤出来自项目目录之外文件的行;更好的是,其中一个标志(3)标记系统头文件(来自-isystem提供的路径的东西,无论是由编译器驱动程序隐式还是显式),所以这也是你可以利用的东西。

例如在Python 3中:

#!/usr/bin/env python3
import sys

skip = False
for l in sys.stdin:
    if not skip:
        sys.stdout.write(l)
    if l.startswith("# "):
        toks = l.strip().split(" ")
        linenum, filename = toks[1:3]
        flags = toks[3:]
        skip = "3" in flags

使用gcc -E foo.c | ./filter.py我得到

# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "foo.c"
# 1 "/usr/include/stdio.h" 1 3 4



# 4 "foo.c"
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);;
return 0;
}

1
投票

保护#includes不被扩展,以文本方式运行预处理器,删除文本预处理器生成的# 1 "<stdint>"等垃圾并重新暴露受保护的#includes。

这个shell函数做到了:

expand_cpp(){
     sed 's|^\([ \t]*#[ \t]*include\)|magic_fjdsa9f8j932j9\1|' "$@" \
     | cpp | sed 's|^magic_fjdsa9f8j932j9||; /^# [0-9]/d'
}

只要你把包含的词放在一起而不是做疯狂的事情就好

#i\
ncl\
u??/
de <iostream>

(上面你可以看到2个反斜杠延续线+ 1个三字形(?? / == \)反斜杠延续线)。

如果你愿意,你可以用同样的方式保护#ifs #ifdefs #ifndefs #endifs和#elses。

适用于您的示例

example.c:

#include <stdio.h>
#define prn(s) printf("this is a macro for printing a string: %s\n", s);

int int(){
char str[5] = "test";
prn(str);
return 0;
}

expand_cpp < example.cexpand_cpp example.c一样,它会产生:

#include <stdio.h>


int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);;
return 0;
}

1
投票

您可以使用-dI来显示#include指令并对预处理器输出进行后处理。

假设您的文件名是foo.c

SOURCEFILE=foo.c
gcc -E -dI "$SOURCEFILE" | awk '
    /^# [0-9]* "/ { if ($3 == "\"'"$SOURCEFILE"'\"") show=1; else show=0; }
    { if(show) print; }'

或者为# line_number "file"抑制所有$SOURCEFILE线:

SOURCEFILE=foo.c
gcc -E -dI "$SOURCEFILE" | awk '
    /^# [0-9]* "/ { ignore = 1; if ($3 == "\"'"$SOURCEFILE"'\"") show=1; else show=0; }
    { if(ignore) ignore=0; else if(show) print; }'

注意:AWK脚本不适用于包含空格的文件名。要使用空格处理文件名,您可以修改AWK脚本以比较$0而不是$3


1
投票

假设文件名为c.c

gcc -E c.c | tail -n +`gcc -E c.c | grep -n -e "#*\"c.c\""  | tail -1 | awk -F: '{print $1}'`

似乎# <number> "c.c"标记每个#include之后的线

当然你也可以将gcc -E c.c保存在一个文件中,不要两次

优点是不要修改源,也不要删除#include之前做gcc -E,只删除从#include生成的顶部到最后一行的所有行...如果我是对的

© www.soinside.com 2019 - 2024. All rights reserved.