我有两个 C 语言文件:foo.c
和 bar.h
(可能还有许多其他文件)。我想要一个在 foo.c
中使用并在 bar.h
中定义的所有预处理器宏的列表。
或者,如果这太困难,甚至可以提供出现在 foo.c
中的所有预处理器宏的列表(但不任何标识符、单词或一段文本)和bar.h
。
我怎样才能获得它?
最佳答案
您可以从 gcc 预处理选项的输出中拼凑这些信息。
要获取文件实际使用的宏列表,您可以使用 -E -dU
选项,该选项会预处理文件,并且还包含 #define
命令任何宏的第一次使用。 (它还为使用 #ifdef
或 #if Defined(...)
测试的未定义名称生成 #undef
命令。)(您必须使用-E
选项 - 仅预处理 - 以便正确处理 -dU
。)
由于 -dU
不会抑制预处理输出,因此您需要通过仅查看 #define
指令来过滤它。对于某些应用程序,您可能还希望通过仅查看相关文件中的实际使用来进一步过滤它,因为报告还包括所包含文件对宏的使用。但在这种情况下,与头文件中实际定义的宏的交集可能就足够了。
因此,要获取 file.c
中使用的宏列表:
gcc -E -dU file.c | grep -Eo '^#define [_A-Za-z][_A-Za-z0-9]*'
(grep -Eo
删除宏的定义。)
您可以使用稍微更慷慨的 grep
调用来近似实际在头文件中定义的宏列表,如下所示:
grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' header.h
即使条件失败,它也会拾取条件部分中定义的宏,并且它将拾取注释中看起来像#define
指令的行。通常,这些都不会造成很多问题。
您可以使用 gcc 的 -E -dM
或 -E -dD
选项来获取 header 中所有定义的列表,但这两个选项也会插入由 header 包含的 header 定义的宏。 (-dM
还包括预定义的宏。)因此,您确实需要做更多的工作来关注头文件实际定义的宏,除非您对定义为包含头文件的结果。
然后你只需要找到两个列表的交集即可。一种方法是提取宏名称 (awk '{print $2}'
),sort -u
独立地排序两个列表,然后合并它们,最后将它们都传递给 uniq -d
仅查看两个列表中的条目。 (以下两者都定义了您将调用 used_and_define foo.c bar.h
的 shell 函数 used_and_define
)
used() {
gcc -E -dU "$1" |
grep -Eo '^#define [_A-Za-z][_A-Za-z0-9]*' |
cut -f2 -d' ' |
sort -u
}
defined() {
grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' "$1" |
awk '{ print $2 }' |
sort -u
}
used_and_defined() {
cat <(used "$1") <(defined "$2") | sort | uniq -d
}
或者您可以使用 awk
完成整个操作
used_and_defined() {
awk '/^[[:space:]]*#[[:space:]]*define/ {
gsub(/[ (].*/, "", $2);
if (NR == FNR) ++macros[$2];
else if (macros[$2]) print $2;
}' \
<(grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' "$2") \
<(gcc -E -dU "$1")
}
关于c - 如何确定 foo.c 中的哪些预处理器宏源自 bar.h?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42900971/