我想知道是否可以用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:如果可能扩大“本地”""
包括而不是扩大“全球”<>
包括将是伟大的
我同意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
命令将删除这些变量声明之间的所有内容。
当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;
}
保护#include
s不被扩展,以文本方式运行预处理器,删除文本预处理器生成的# 1 "<stdint>"
等垃圾并重新暴露受保护的#include
s。
这个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个三字形(?? / == \)反斜杠延续线)。
如果你愿意,你可以用同样的方式保护#if
s #ifdef
s #ifndef
s #endif
s和#else
s。
适用于您的示例
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.c
或expand_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;
}
您可以使用-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
。
假设文件名为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
生成的顶部到最后一行的所有行...如果我是对的