如何确定 foo.c 中的哪些预处理器宏源自 bar.h?
How can I determine which preprocessor macros in foo.c originate in bar.h?
我有两个 C 语言文件:foo.c
和 bar.h
(可能还有许多其他文件)。我想要在 foo.c
中使用并在 bar.h
中定义的所有预处理器宏的列表。
或者,如果这太难了,即使是出现在 foo.c
和 bar.h
.
我怎样才能得到它?
一个策略(公认的麻烦)可以是:
foreach 宏标识符 SOME_MACRO in bar.h
, 运行
gcc -E -DSOME_MACRO=recognizable_value foo.c | grep recognizable_value
即预处理源并检测是否发生扩展。请注意,这不适用于仅在 #if
指令等中使用的宏。
您可以从 gcc 预处理选项的输出中拼凑出这些信息。
要获取文件实际使用的宏列表,您可以使用 -E -dU
选项,它会对文件进行预处理,并在第一个 use 处包含 #define
命令 任何宏。 (它还会为使用 #ifdef
或 #if defined(...)
测试的未定义名称生成 #undef
命令。)(您必须使用 -E
选项——仅预处理——用于 -dU
妥善处理。)
由于 -dU
不抑制预处理输出,您需要通过仅查看 #define
指令来过滤它。对于某些应用程序,您可能还希望通过仅查看相关文件中的实际用途来进一步过滤它,因为报告也包括所包含文件对宏的使用。但在这种情况下,与 header 文件中实际定义的宏的交集可能就足够了。
因此要获取 file.c
中使用的宏列表:
gcc -E -dU file.c | grep -Eo '^#define [_A-Za-z][_A-Za-z0-9]*'
(grep -Eo
删除了宏的定义。)
您可以使用更慷慨的 grep
调用来近似 header 文件中实际定义的宏列表,如下所示:
grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' header.h
即使条件失败,它也会选取条件部分中定义的宏,并且会选取注释中看起来像 #define
指令的行。通常,这些都不会引起很多问题。
您可以使用 gcc 的 -E -dM
或 -E -dD
选项来获取 header 中所有定义的列表,但这两者也会插入 [=58] 定义的宏=]s 包含在 header 中。 (-dM
还包括预定义的宏。)所以你真的需要做更多的工作来关注 header 文件实际定义的宏,除非你对定义为包含 header 文件的结果。
然后你只需要找到两个列表的交集。一种方法是将宏名称(awk '{print }'
)、sort -u
两个列表独立提取然后合并,最后将它们都通过uniq -d
传递,只看两个列表中的条目。 (以下都定义了 shell 函数 used_and_defined
,您将调用 used_and_defined foo.c bar.h
)
used() {
gcc -E -dU "" |
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]*' "" |
awk '{ print }' |
sort -u
}
used_and_defined() {
cat <(used "") <(defined "") | sort | uniq -d
}
或者您可以使用 awk
完成整个操作
used_and_defined() {
awk '/^[[:space:]]*#[[:space:]]*define/ {
gsub(/[ (].*/, "", );
if (NR == FNR) ++macros[];
else if (macros[]) print ;
}' \
<(grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' "") \
<(gcc -E -dU "")
}
一个gcc
-specific(但clang
具有相同语义的相同选项)除了-E
之外还使用-dD
:
gcc -E -dD -o foo.i [other options] foo.c
将在输出中保留 #define
行以及 # nnn "/path/to/file.h"
指令,以便您应该能够分辨出哪个宏属于哪个文件。如果你想提取来自 bar.h
的宏,这取决于你希望在 bar.h
中找到的宏数量,你最喜欢的编辑器的搜索命令可能就足够了,或者一个小的 awk/perl/python/...脚本会有所帮助。
我有两个 C 语言文件:foo.c
和 bar.h
(可能还有许多其他文件)。我想要在 foo.c
中使用并在 bar.h
中定义的所有预处理器宏的列表。
或者,如果这太难了,即使是出现在 foo.c
和 bar.h
.
我怎样才能得到它?
一个策略(公认的麻烦)可以是:
foreach 宏标识符 SOME_MACRO in bar.h
, 运行
gcc -E -DSOME_MACRO=recognizable_value foo.c | grep recognizable_value
即预处理源并检测是否发生扩展。请注意,这不适用于仅在 #if
指令等中使用的宏。
您可以从 gcc 预处理选项的输出中拼凑出这些信息。
要获取文件实际使用的宏列表,您可以使用 -E -dU
选项,它会对文件进行预处理,并在第一个 use 处包含 #define
命令 任何宏。 (它还会为使用 #ifdef
或 #if defined(...)
测试的未定义名称生成 #undef
命令。)(您必须使用 -E
选项——仅预处理——用于 -dU
妥善处理。)
由于 -dU
不抑制预处理输出,您需要通过仅查看 #define
指令来过滤它。对于某些应用程序,您可能还希望通过仅查看相关文件中的实际用途来进一步过滤它,因为报告也包括所包含文件对宏的使用。但在这种情况下,与 header 文件中实际定义的宏的交集可能就足够了。
因此要获取 file.c
中使用的宏列表:
gcc -E -dU file.c | grep -Eo '^#define [_A-Za-z][_A-Za-z0-9]*'
(grep -Eo
删除了宏的定义。)
您可以使用更慷慨的 grep
调用来近似 header 文件中实际定义的宏列表,如下所示:
grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' header.h
即使条件失败,它也会选取条件部分中定义的宏,并且会选取注释中看起来像 #define
指令的行。通常,这些都不会引起很多问题。
您可以使用 gcc 的 -E -dM
或 -E -dD
选项来获取 header 中所有定义的列表,但这两者也会插入 [=58] 定义的宏=]s 包含在 header 中。 (-dM
还包括预定义的宏。)所以你真的需要做更多的工作来关注 header 文件实际定义的宏,除非你对定义为包含 header 文件的结果。
然后你只需要找到两个列表的交集。一种方法是将宏名称(awk '{print }'
)、sort -u
两个列表独立提取然后合并,最后将它们都通过uniq -d
传递,只看两个列表中的条目。 (以下都定义了 shell 函数 used_and_defined
,您将调用 used_and_defined foo.c bar.h
)
used() {
gcc -E -dU "" |
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]*' "" |
awk '{ print }' |
sort -u
}
used_and_defined() {
cat <(used "") <(defined "") | sort | uniq -d
}
或者您可以使用 awk
used_and_defined() {
awk '/^[[:space:]]*#[[:space:]]*define/ {
gsub(/[ (].*/, "", );
if (NR == FNR) ++macros[];
else if (macros[]) print ;
}' \
<(grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' "") \
<(gcc -E -dU "")
}
一个gcc
-specific(但clang
具有相同语义的相同选项)除了-E
之外还使用-dD
:
gcc -E -dD -o foo.i [other options] foo.c
将在输出中保留 #define
行以及 # nnn "/path/to/file.h"
指令,以便您应该能够分辨出哪个宏属于哪个文件。如果你想提取来自 bar.h
的宏,这取决于你希望在 bar.h
中找到的宏数量,你最喜欢的编辑器的搜索命令可能就足够了,或者一个小的 awk/perl/python/...脚本会有所帮助。