使用旧内容重新定义宏/使文件包含计数器

时间:2017-06-09 22:08:20

标签: c c-preprocessor

我想计算一个特定文件的包含数量。

我的第一个想法是定义一个包含计数的宏,并在包含特定文件时重新定义它。我必须找到一种扩展宏的方法,再次使用同名的新定义,否则它的旧值将被undef简单地销毁。有没有办法在定义宏时扩展宏。或者还有其他方法来计算包含文件吗?

FILE main.c:

#define INCLUDE_COUNT 0

// some other files include the file include_counter.h here

您会认为编译器可以将INCLUDE_COUNT替换为第一行中的0或其中一个重定义,但它不会,因为宏在非宏中使用时会扩展宏定义中的宏代码。

FILE include_counter.h:

#define OLD_INCLUDE_COUNT (INCLUDE_COUNT)
#undef INCLUDE_COUNT
#define INCLUDE_COUNT (OLD_INCLUDE_COUNT + 1)
// INCLUDE_COUNT would be expanded to ((INCLUDE_COUNT) + 1)

2 个答案:

答案 0 :(得分:2)

有没有办法在定义宏时扩展宏。

是。但请注意......如果您的符号具有外部链接,则将此作为生成唯一符号的方法可能会导致意外的链接器问题。

概述

这里的关键问题是宏不是变量。对于变量,如果我有x=3*3; y=x;,那么我将x的分配给y。对于宏,如果我有#define PPX 3*3 #define PPY PPX,那么我实际上将PPX分配给PPY。如果我然后评估PPY,它会扩展为PPX,然后扩展为3*3,但仅限于PPX当前定义为3*3

然而,有一种解决方法。预处理器可以评估表达式;它只是使用条件指令来这样做。但由于这可以分支,我们可以根据PPX's 定义宏有条件地(而不是替换列表 >)。例如:

#if (PPX)%10==9
#  define PPX_DIGIT_0 9
#elif (PPX)%10==8
#  define PPX_DIGIT_0 8
...

因此,PPY严格依赖PPX定义为3*3来扩展为3*3;由于PPX_DIGIT_0 字面定义为9 PPX可能未定义,PPX_DIGIT_0仍会扩展为9.还请注意条件播放减少表达的作用; (3*3)%10等于9,导致9分支被击中。这本身就失去了表达,只接受了我们想要的评估。

这就是主意。在实践中,这需要相当数量的代码;幸运的是,boost的预处理器库已经为你完成了,所以这里有两种使用boost的方法:

方法1:使用增强插槽

include_counter.h

#include <boost/preprocessor/slot/slot.hpp>
#if !(INCLUDE_COUNT)
# define INCLUDE_COUNT 0
# define BOOST_PP_VALUE INCLUDE_COUNT
# include BOOST_PP_ASSIGN_SLOT(1)
# undef  BOOST_PP_VALUE
# undef  INCLUDE_COUNT
# define INCLUDE_COUNT BOOST_PP_SLOT(1)
#endif
#define BOOST_PP_VALUE 1+INCLUDE_COUNT
#include BOOST_PP_ASSIGN_SLOT(1)

Boost槽评估宏并使用特殊的内部状态存储结果。你得到5个插槽(上面的代码是使用插槽1),所以你可以存储5个数字。这个解决方案只是在第一个包含增量之前将插槽初始化为0,然后基本上只增加。

方法2:使用升压计数器

include_counter.h

#if !(INCLUDE_COUNT)
# include <boost/preprocessor/slot/counter.hpp>
# define INCLUDE_COUNT BOOST_PP_COUNTER
#endif
#include BOOST_PP_UPDATE_COUNTER()

同样的想法,虽然它“消耗”增强反击。

两种提升解决方案都采用我刚才描述的方法。还有一个增量增量宏;我可以随意忽略这一点,因为(a)你无论如何都要进行评估,而且(b)增强增量有点笨拙(最大限制为256)。

您也可以推出自己的解决方案。但是当你完成后,无论如何它都会与boost的解决方案类似。 (优点是,您的新“插槽”将独立于增强计数器和增强插槽)。

答案 1 :(得分:1)

另一种方法是不使用宏而是使用编译器。许多编译器都有一个&#34; show includes&#34;旗。例如,在gcc中,它是-H。对于visual studio,它是/ showincludes。只需将编译器输出传递给文件并计算行数。

# linux
gcc -H ... fred.c 1> incs.txt 2>&1
wc -l incs.txt

rem Windows
cl /showincludes ... fred.c 1> incs.txt 2>&1
find /v /c "" < incs.txt

# powershell
cl /showincludes ... fred.c 1> incs.txt 2>&1
get-content incs.txt | measure-object -l

请注意,如果多次包含该文件,则会对该文件进行计数,即使由于警卫而未进行处理也是如此。