我正在尝试对 C 代码中的宏定义进行优化。同样,我需要提取 C 文件中存在的所有宏,并且需要查找此特定宏定义出现的次数。
我的宏定义的格式是这样的
#定义 MACRO_NAME DEFN_LINE1\ DEFN_LINE2\ DEFN_LINE3
所以我想我的逻辑是
- 使用正则表达式查找以“#define”开头并以“\”结尾的行列表,将上述输出重定向到 MacroLineExtract.txt 文件
- 从 MacroLineExtract.txt ==> MACRO_NAME DEFN_LINE1\ 中删除所有“#define”
- 删除空格 ===> MACRO_NAME 之后的尾随字符串
- 将以上输出保存到文件 Macros.txt 中,该文件现在仅保存我的代码中存在的 MACROS 列表
- 编写一个 bash 脚本,从 Macros.txt 中取出一行又一行,并查找 MACRO_NAME 在我的代码中出现了多少次。
你能帮我写一个正则表达式/awk来查找我的c文件中以“#define”开头并以“\”结尾的所有宏吗?如果您有更好的逻辑,请提出相同的建议。
答案1
使用旺盛的ctags:
$ ectags --c-kinds=d *.[ch]
ectags
是“标签文件”的增强版本ctags
,etags
用于创建“标签文件”,Vi/Vim 或 Emacs 等编辑器可以使用该文件来轻松导航源代码。它了解 C 语法规则,因此能够为您解析 C 代码(这样您就不必担心正则表达式)。
我们--c-kinds=d
告诉我们ectags
只关心#define
C 代码中的行。
现在,您在当前目录中拥有一个名为的文件,tags
其中包含以下内容:
DEVELOPER bayes.h 225;" d
DIFFERENT bayes.h 227;" d
DIR_MIN bayes.h 338;" d
DNA bayes.h 242;" d
DOLLAR bayes.h 309;" d
DOLLO bayes.h 276;" d
DOWN bayes.h 215;" d
也就是说,每一行(除了少数标题行)都标识宏的名称、找到该宏的源文件以及行号。如果在多个文件中定义了宏,则每次出现时都会列出一次。最后一个d
是标签类型指示器(这些都是#define
s)。
如果您只想计算每个宏被定义的次数:
$ cut -f 1 tags | uniq -c
答案2
awk
可以进行解析和计算在单个操作中,假设您可以传递所有所需的文件名而不超过 ARG_MAX:
awk '$1=="#define"&&/\\$/ {n[$2]++} END {for(i in n) print n[i],i}' *.[ch]
# this includes #define's that are indented with whitespace,
# which the C language allows. If you really want only #defines
# that start exactly in column 1, use /^#define /&&/\\$/
# if you want the columns to line up change the print to something like
# printf "%6d %s\n",x[i],i
答案3
如果您的文件中存在这样的行:
#定义 MACRO_NAME DEFN_LINE1\
那么这将获得 MACRO_NAME 的唯一值:
cat yourCfile | grep '#define' | awk '{print $2}' | sort -u > macro_names
grep 正在获取包含“#define”的行
awk 将一行中的每个字符串视为一个新字段,使用空格/空格作为默认字段分隔符。所以这里我们只是使用 awk 打印“#define MACRO_NAME DEFN_LINE1\”中的第二个字段,即“MACRO_NAME”。
sort -u > Macro_names 只是删除所有重复项并将所有内容输出到文件中。
并循环遍历宏名称列表并查找包含该宏名称的行数:
for macro in $(cat macro_names); do
count=$(cat yourCfile | grep $macro | wc -l);
echo $macro appears $count times
done
带有“-l”标志的“wc”命令打印从标准输入接收的行数。
答案4
sed '/#define/,\
/^\(.*[^\]\)*$/N
/\n\\/P;D'