如何确定foo.c中的哪些预处理器宏来自bar.h?

时间:2022-11-25 10:57:45

I have two C language files: foo.c and bar.h (and possibly many other files). I want a list of all preprocessor macros which are used in foo.c and defined in bar.h.

我有两个C语言文件:foo.c和bar.h(可能还有很多其他文件)。我想要一个在foo.c中使用并在bar.h中定义的所有预处理器宏的列表。

Alternatively, if that's too difficult, even a list of all preprocessor macros (but not any identifier, word or piece of text) which appear in both foo.c and bar.h.

或者,如果这太难了,甚至包括出现在foo.c和bar.h中的所有预处理器宏(但不是任何标识符,单词或文本片段)的列表。

How can I obtain that?

我怎么能得到它?

3 个解决方案

#1


2  

You can piece this information together from the output of gcc's preprocessing options.

您可以从gcc的预处理选项的输出中将这些信息拼凑在一起。

To get the list of macros actually used by a file, you can use the -E -dU options, which preprocesses the file and also includes #define commands at the first use of any macro. (It also produces #undef commands for undefined names tested with #ifdef or #if defined(...).) (You must use the -E option -- only preprocess -- for -dU to be handled properly.)

要获取文件实际使用的宏列表,可以使用-E -dU选项,它们预处理文件,并在首次使用任何宏时包含#define命令。 (它还为使用#ifdef或#if defined(...)测试的未定义名称生成#undef命令。)(必须使用-E选项 - 只能预处理 - for -dU才能正确处理。)

Since -dU does not suppress the preprocessed output, you need to filter it by looking only at the #define directives. For some applications, you might also want to further filter it by looking only at the uses actually in the file in question, since the report includes uses of macros by included files as well. But in this case, the intersection with the macros actually defined in the header file is probably sufficient.

由于-dU不会抑制预处理输出,因此您需要通过仅查看#define指令来过滤它。对于某些应用程序,您可能还希望通过仅查看相关文件中的实际用途来进一步过滤它,因为该报告还包括按所包含文件使用宏。但在这种情况下,与头文件中实际定义的宏的交集可能就足够了。

So to get a list of used macros in file.c:

所以要在file.c中获取使用过的宏列表:

gcc -E -dU file.c | grep -Eo '^#define [_A-Za-z][_A-Za-z0-9]*'

(The grep -Eo removes the definition of the macro.)

(grep -Eo删除了宏的定义。)

You can approximate a list of macros actually defined in a header file using a slightly more generous grep invocation, something like this:

您可以使用稍微更慷慨的grep调用来近似实际在头文件中定义的宏列表,如下所示:

grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' header.h

That will pick up macros defined in conditional sections even if the conditional fails, and it will pick up lines in comments which look like #define directives. Usually, neither of those will cause many problems.

即使条件失败,它也将获取在条件部分中定义的宏,并且它将在注释中拾取看起来像#define指令的行。通常,这些都不会导致很多问题。

You could use gcc's -E -dM or -E -dD options to get a list of all defines in a header, but both of those will also insert the macros defined by headers included by the header. (-dM also includes the predefined macros.) So you would really need to do some more work to focus on the macros actually defined by the header file, unless you are interested in all the macros defined as a result of including the header file.

您可以使用gcc的-E -dM或-E -dD选项来获取标头中所有定义的列表,但这两个选项也将插入由标头包含的标头定义的宏。 (-dM还包括预定义的宏。)所以你真的需要做更多的工作来专注于头文件实际定义的宏,除非你对由于包含头文件而定义的所有宏感兴趣。

Then you just need to find the intersection of the two lists. One way is to exract the macro names (awk '{print $2}'), sort -u both lists independently and then merge them, and finally pass them both through uniq -d to only look at the entries in both lists. (Both the following define the shell function used_and_defined which you would invoke used_and_defined foo.c bar.h)

然后你只需要找到两个列表的交集。一种方法是提取宏名称(awk'{print $ 2}'),独立排序-u两个列表然后合并它们,最后通过uniq -d传递它们,只查看两个列表中的条目。 (以下两个定义了shell函数used_and_defined,您将调用used_and_defined foo.cbar.h)

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
}

Or you could do the whole operation with awk

或者你可以使用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")
}

#2


1  

One strategy (admittedly cumbersome) could be:

一种策略(公认的繁琐)可能是:

foreach macro identifier SOME_MACRO in bar.h, run

在bar.h中的foreach宏标识符SOME_MACRO,运行

gcc -E -DSOME_MACRO=recognizable_value foo.c | grep recognizable_value

i.e. preprocess the source and detect if an expansion happened. Note that this does not work for macros only used in #if directives and such.

即预处理源并检测是否发生了扩展。请注意,这不适用于仅在#if指令等中使用的宏。

#3


0  

A gcc-specific (but clang has the same option with the same semantics) is to use -dD in addition to -E:

特定于gcc(但clang具有相同语义的相同选项)除-E外还使用-dD:

gcc -E -dD -o foo.i [other options] foo.c

will keep #define lines in the output, together with # nnn "/path/to/file.h" directives, so that you should be able to tell which macro belongs to which file. If you want to extract the macros that come from bar.h, Depending on the number of macros you expect to find in bar.h, the search command of your favorite editor might be sufficient, or a small awk/perl/python/... script would help.

将#ndnine行与#nnn“/ path/to/file.h”指令一起保留在输出中,以便您能够分辨哪个宏属于哪个文件。如果要提取来自bar.h的宏,根据您希望在bar.h中找到的宏的数量,您喜欢的编辑器的搜索命令可能就足够了,或者是一个小的awk / perl / python /。 ..脚本会有所帮助。

#1


2  

You can piece this information together from the output of gcc's preprocessing options.

您可以从gcc的预处理选项的输出中将这些信息拼凑在一起。

To get the list of macros actually used by a file, you can use the -E -dU options, which preprocesses the file and also includes #define commands at the first use of any macro. (It also produces #undef commands for undefined names tested with #ifdef or #if defined(...).) (You must use the -E option -- only preprocess -- for -dU to be handled properly.)

要获取文件实际使用的宏列表,可以使用-E -dU选项,它们预处理文件,并在首次使用任何宏时包含#define命令。 (它还为使用#ifdef或#if defined(...)测试的未定义名称生成#undef命令。)(必须使用-E选项 - 只能预处理 - for -dU才能正确处理。)

Since -dU does not suppress the preprocessed output, you need to filter it by looking only at the #define directives. For some applications, you might also want to further filter it by looking only at the uses actually in the file in question, since the report includes uses of macros by included files as well. But in this case, the intersection with the macros actually defined in the header file is probably sufficient.

由于-dU不会抑制预处理输出,因此您需要通过仅查看#define指令来过滤它。对于某些应用程序,您可能还希望通过仅查看相关文件中的实际用途来进一步过滤它,因为该报告还包括按所包含文件使用宏。但在这种情况下,与头文件中实际定义的宏的交集可能就足够了。

So to get a list of used macros in file.c:

所以要在file.c中获取使用过的宏列表:

gcc -E -dU file.c | grep -Eo '^#define [_A-Za-z][_A-Za-z0-9]*'

(The grep -Eo removes the definition of the macro.)

(grep -Eo删除了宏的定义。)

You can approximate a list of macros actually defined in a header file using a slightly more generous grep invocation, something like this:

您可以使用稍微更慷慨的grep调用来近似实际在头文件中定义的宏列表,如下所示:

grep -Eo '^\s*#\s*define\s+[_A-Za-z][_A-Za-z0-9]*' header.h

That will pick up macros defined in conditional sections even if the conditional fails, and it will pick up lines in comments which look like #define directives. Usually, neither of those will cause many problems.

即使条件失败,它也将获取在条件部分中定义的宏,并且它将在注释中拾取看起来像#define指令的行。通常,这些都不会导致很多问题。

You could use gcc's -E -dM or -E -dD options to get a list of all defines in a header, but both of those will also insert the macros defined by headers included by the header. (-dM also includes the predefined macros.) So you would really need to do some more work to focus on the macros actually defined by the header file, unless you are interested in all the macros defined as a result of including the header file.

您可以使用gcc的-E -dM或-E -dD选项来获取标头中所有定义的列表,但这两个选项也将插入由标头包含的标头定义的宏。 (-dM还包括预定义的宏。)所以你真的需要做更多的工作来专注于头文件实际定义的宏,除非你对由于包含头文件而定义的所有宏感兴趣。

Then you just need to find the intersection of the two lists. One way is to exract the macro names (awk '{print $2}'), sort -u both lists independently and then merge them, and finally pass them both through uniq -d to only look at the entries in both lists. (Both the following define the shell function used_and_defined which you would invoke used_and_defined foo.c bar.h)

然后你只需要找到两个列表的交集。一种方法是提取宏名称(awk'{print $ 2}'),独立排序-u两个列表然后合并它们,最后通过uniq -d传递它们,只查看两个列表中的条目。 (以下两个定义了shell函数used_and_defined,您将调用used_and_defined foo.cbar.h)

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
}

Or you could do the whole operation with awk

或者你可以使用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")
}

#2


1  

One strategy (admittedly cumbersome) could be:

一种策略(公认的繁琐)可能是:

foreach macro identifier SOME_MACRO in bar.h, run

在bar.h中的foreach宏标识符SOME_MACRO,运行

gcc -E -DSOME_MACRO=recognizable_value foo.c | grep recognizable_value

i.e. preprocess the source and detect if an expansion happened. Note that this does not work for macros only used in #if directives and such.

即预处理源并检测是否发生了扩展。请注意,这不适用于仅在#if指令等中使用的宏。

#3


0  

A gcc-specific (but clang has the same option with the same semantics) is to use -dD in addition to -E:

特定于gcc(但clang具有相同语义的相同选项)除-E外还使用-dD:

gcc -E -dD -o foo.i [other options] foo.c

will keep #define lines in the output, together with # nnn "/path/to/file.h" directives, so that you should be able to tell which macro belongs to which file. If you want to extract the macros that come from bar.h, Depending on the number of macros you expect to find in bar.h, the search command of your favorite editor might be sufficient, or a small awk/perl/python/... script would help.

将#ndnine行与#nnn“/ path/to/file.h”指令一起保留在输出中,以便您能够分辨哪个宏属于哪个文件。如果要提取来自bar.h的宏,根据您希望在bar.h中找到的宏的数量,您喜欢的编辑器的搜索命令可能就足够了,或者是一个小的awk / perl / python /。 ..脚本会有所帮助。