如何显示';预处理';代码忽略GCC中的includes
我想知道是否可以使用gcc输出“预处理”代码,但“忽略”(不扩展)包括: 是的,我有一个主要问题:如何显示';预处理';代码忽略GCC中的includes,c,linux,gcc,c-preprocessor,C,Linux,Gcc,C Preprocessor,我想知道是否可以使用gcc输出“预处理”代码,但“忽略”(不扩展)包括: 是的,我有一个主要问题: #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; } 我只想输出: #include <stdio.h> int int(){ 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;
}
我只想输出:
#include <stdio.h>
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}
PS:如果可以扩展“本地”
“
包含,而不扩展“全局”
包含,那就太好了。当cpp扩展包含时,它会将错误追溯到原始文件
您可以添加一个后期处理步骤(可以用任何脚本语言编写,如果您愿意,甚至可以用C编写),以仅解析行标记并过滤掉来自项目目录之外的文件的行;更好的是,其中一个标志(3)标记了系统头文件(来自通过-issystem
提供的路径的内容,可以是编译器驱动程序隐式的,也可以是显式的),因此您也可以利用它
例如,在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-efoo.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“foo.c”
# 1 ""
# 1 ""
# 31 ""
#1“/usr/include/stdc predef.h”1 3 4
#1“foo.c”
#1“/usr/include/stdio.h”1 3 4
#4“foo.c”
int(){
字符str[5]=“测试”;
printf(“这是一个用于打印字符串的宏:%s\n”,str);;
返回0;
}
假设文件名为c.c
:
gcc -E c.c | tail -n +`gcc -E c.c | grep -n -e "#*\"c.c\"" | tail -1 | awk -F: '{print $1}'`
似乎#“c.c”
会在每个#include
之后标记行
当然,您也可以将gcc-ec.c
保存在一个文件中,以避免重复两次
优点是在执行
gcc-E
之前,不修改源代码,也不删除#include
,只删除从顶部到最后由#include
生成的所有行。。。如果我是对的我同意Matteo Italia的评论,即如果您只是阻止扩展#include
指令,那么生成的代码将不代表编译器实际看到的内容,因此它在故障排除中的作用有限
这里有一个解决这个问题的办法。在include前后添加变量声明。任何合理唯一的变量都可以
int begin_includes_tag;
#include <stdio.h>
... other includes
int end_includes_tag;
sed
命令将删除这些变量声明之间的所有内容。保护#include
s不被扩展,以文本方式运行预处理器,删除#1”“
等。文本预处理器生成垃圾,并重新扩展受保护的#include
s
此shell函数执行以下操作:
expand_cpp(){
sed 's|^\([ \t]*#[ \t]*include\)|magic_fjdsa9f8j932j9\1|' "$@" \
| cpp | sed 's|^magic_fjdsa9f8j932j9||; /^# [0-9]/d'
}
只要你把include这个词放在一起,而不是做一些疯狂的事情,比如
#i\
ncl\
u??/
de <iostream>
与expand_cpp
或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;
}
#包括
int(){
字符str[5]=“测试”;
printf(“这是一个用于打印字符串的宏:%s\n”,str);;
返回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; }'
或者要抑制$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以前的许多答案都指向使用跟踪
指令
它实际上是经典Unix中的一行程序(使用awk
):
gcc-E file.c|awk'/#[1-9][0-9]*“file.c/{skip=0;next}/#[1-9][0-9]*”*“/{skip=1}(skipTL;DR
将文件名分配给fname
并在shell中运行以下命令。在整个过程中,假定fname
是包含要处理的源文件的sh
变量
fname=file_to_process.c ;
grep -G '^#include' <./"$fname" ;
grep -Gv '^#include[ ]*<' <./"$fname" | gcc -x c - -E -o - $(grep -G '^#include[ ]*<' <./"$fname" | xargs -I {} -- expr "{}" : '#include[ ]*<[ ]*\(.*\)[ ]*>' | xargs -I {} printf '-imacros %s ' "{}" ) | grep -Ev '^([ ]*|#.*)$'
注意:一般来说,gcc不会扩展打算作为宏的标记,但是缺少定义。然而,断言
恰好完全扩展:\uuuuuuu扩展
是编译器选项,\uuuuu断言
是函数,\uuuu漂亮的函数
是字符串文字
自动化
以前的方法是可行的,但可能会很乏味
每个#include
都需要手动从文件中删除,并且
它必须作为-imacros
的参数添加到gcc
调用中
第一部分很容易编写脚本:pipegrep-Gv'^#include[]*将include封装在#ifndef XXXX…#endif
中,并将-dxxx
与-E
?grep-v“#include”一起传递noinclude.c;gcc-E noinclude.c
如果您使用标准头中的宏,这两种方法都会有问题,因为标准头不会被扩展。@bruno可能可以使用sed
来完成,而不需要中间文件……但我不会考虑它:)您可以随时注释掉系统包含的文件。无需添加实际变量,甚至两条包含GUID的注释都可以。@MatteoItalia谢谢您的想法。我一开始试着使用注释,但很快就意识到注释将被预处理器剥离。我不知道GUID注释不会被剥离。呃,很抱歉,我不知道注释剥离发生在预处理器级别,请忽略我的注释!我会这样做,将“声明标记”放在#ifdef DEBUG
中,因为它很简单,而且我不需要对SED做很多事情(我不熟悉),也因为它允许我轻松地“取消标记”我想要的包process@MatteoItalia,gnucpp
程序可以进行预处理,同时使用-C标志(或-CC)保留注释,所以我觉得你的技巧很有用。它很有效,只需要添加-n
作为第一个tail的参数,我也喜欢它,因为它的语法清晰易记,而且容易理解adapt@DDS啊,对不起,对我来说,“+”和“-n+”也一样,我还是编辑我的答案。如果我的答案是正确的
#include <stdio.h>
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);;
return 0;
}
SOURCEFILE=foo.c
gcc -E -dI "$SOURCEFILE" | awk '
/^# [0-9]* "/ { if ($3 == "\"'"$SOURCEFILE"'\"") show=1; else show=0; }
{ if(show) print; }'
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; }'
fname=file_to_process.c ;
grep -G '^#include' <./"$fname" ;
grep -Gv '^#include[ ]*<' <./"$fname" | gcc -x c - -E -o - $(grep -G '^#include[ ]*<' <./"$fname" | xargs -I {} -- expr "{}" : '#include[ ]*<[ ]*\(.*\)[ ]*>' | xargs -I {} printf '-imacros %s ' "{}" ) | grep -Ev '^([ ]*|#.*)$'
printf 'int main(){\nassert(1);\nreturn 0;}\n' | gcc -x c -E - -imacros assert.h | grep -Ev '^([ ]*|#.*)$'
printf '' > std ;
for header in *.h ; do
grep -G '^#include[ ]*<' <./$header >> std ;
sed -i '/#include[ ]*</d' $header ;
done;
for source in *.c ; do
cat std > tmp;
cat $source >> tmp;
mv -f tmp $source ;
done
#ifndef H1H
#define H1H
#include <stdio.h>
#include <limits.h>
#define H1 printf("H1:%i\n", h1_int)
int h1_int=INT_MAX;
#endif
#ifndef H2H
#define H2H
#include <stdio.h>
#include "h1.h"
#define H2 printf("H2:%i\n", h2_int)
int h2_int;
#endif
#include <assert.h>
#include "h1.h"
#include "h2.h"
int main(){
assert(1);
H1;
H2;
}
fname="$1"
printf '' > std ;
for source in *.[ch] ; do
grep -G '^#include[ ]*<' <./$source >> std ;
sed -i '/#include[ ]*</d' $source ;
sort -u std > std2;
mv -f std2 std;
done;
for source in *.c ; do
cat std > tmp;
cat $source >> tmp;
mv -f tmp $source ;
done
grep -G '^#include[ ]*<' <./"$fname" ;
grep -Gv '^#include[ ]*<' <./"$fname" | gcc -x c - -E -o - $(grep -G '^#include[ ]*<' <./"$fname" | xargs -I {} -- expr "{}" : '#include[ ]*<[ ]*\(.*\)[ ]*>' | xargs -I {} printf '-imacros %s ' "{}" ) | grep -Ev '^([ ]*|#.*)$'
#include <assert.h>
#include <limits.h>
#include <stdio.h>
int h1_int=0x7fffffff;
int h2_int;
int main(){
((void) sizeof ((
1
) ? 1 : 0), __extension__ ({ if (
1
) ; else __assert_fail (
"1"
, "<stdin>", 4, __extension__ __PRETTY_FUNCTION__); }))
;
printf("H1:%i\n", h1_int);
printf("H2:%i\n", h2_int);
}