如何找到一些宏的来源
定义宏有很多地方。当宏在我们自己的项目中定义时,很容易找到它们的定义位置。 但是,当我尝试学习一些着名的开源项目时,我经常被这个问题所困扰:在哪里找到宏的来源,如果我不能得到它的定义,我将无法理解它们中的一些(例如其中一些可以猜到他们的名字)。 例如,来自apache的一些声明:
#if defined(__osf__) && defined(__alpha), #elif defined(__NSIG)
据我所知,我知道宏有一些可能的起源地:
- 来自这个项目本身,在一些源文件中(这是最简单的,因为我们可以通过一些工具找到它)
- 从某些第三个lib的头文件中,我们可以grep它
- 来自c / c ++标准头文件(它们在linux中的哪个位置?)
- 来自os(他们在Linux中的位置?)
- 由配置工具自动生成(它很苦,我不知道)
- 从gcc / g ++这样的编译工具,或者在makefile中我们可以定义一些宏
我有一些问题需要咨询:
- 如何区分os定义和gcc / g ++定义和配置工具生成的宏?它们分别具有一些特征吗?
- 如何找到os或标准C或编译器定义的源代码? 例如,使用
grep
或find
实用程序 - 如果通过梳理整个机器(
cd /;grep __strange___ -r
)找不到像__strange___
这样的宏,这是什么意思?
感谢您告诉原则和方法来区分它们,并找到它们的来源!
找到宏定义位置的一种简单,快速的方法是重新定义宏并检查编译器的警告/错误消息。
#include #define min(a,b) nonsense mintest.cpp(3) : warning C4005: 'min' : macro redefinition C:\Programme\Microsoft SDKs\Windows\v6.0A\include\windef.h(194) : see previous definition of 'min'
- 如何区分os定义和gcc / g ++定义和配置工具生成的宏?它们分别具有一些特征吗?
绝大多数都是在某个头文件中定义的。 gcc -dN -E
在这里可以提供帮助。 警告:如果使用这种方法,则需要使用相同的包含路径,相同的-D
命令行选项,相同的环境变量(如CPATH
,…)来调用gcc -dN -E
,就像在执行时一样您将源代码编译为目标文件。
- 如何找到os或标准C或编译器定义的源代码? 例如,使用grep或find实用程序
RTFM。 阅读精细手册。
- 如果通过梳理整个机器
(cd /;grep __strange___ -r)
找不到像__strange__
这样的宏,这是什么意思?
它可能只是意味着您的计算机上未定义该符号。 假设有问题的代码来自一些开源软件包,它针对不同系统,不同编译器,其中一些不完全符合C ++标准。 典型的方法是在代码的关键部分使用#ifdef __some_bizarre_os__
。 该符号仅在运行Bizarre OS的机器上定义 – 而不是在您的机器上定义。
不幸的是,这不是唯一的情况。 即使您的grep无法在任何地方找到它,也可能很好地定义符号。 makefile可以连接两个字符串-D__str
和ange__
以形成编译器的单个命令行参数。 选项-D__strange__
可能隐藏在makefile使用的一个环境变量中。 某些项目所要求的〜/ .tcshrc文件可能令人难以置信。
更新
gcc -dM -E
显示宏的定义,但不显示定义的位置。 更好的选择是使用gcc -dN -E
然后过滤掉不以#
开头的行。
gcc编译器定义的宏可以通过显示
gcc -dM -E ac
除此之外,它们都来自包含的文件和来源。
如果找不到宏,则表示条件将被评估为false。
您还可以使用-v选项,它显示它找到其默认包含目录的位置。
要找出宏来自哪个文件:
gcc -E $your_compile_options $your_c_file | \ egrep "^# " | grep -v '<'| cut -f 2 -d '"' | \ sort | uniq | while read line do grep -l $your_macro $line done
您应该使用像Eclipse这样的IDE,只需右键单击宏并单击Open Declaration,它就会将您发送到文件并定义宏。
有时某些宏甚至没有在头文件中定义,因为它们作为gnu编译器的标志给出(例如:-DMYMACRO)。
看起来这些宏是编译常量。
优良作法是使用这些宏告诉编译器需要编译这部分代码,并且不编译这部分代码。
如果您无法在项目工作区中搜索它们,那么您应该完成程序流程并确定应用程序所需的代码部分并定义相应的宏。
例如;
#ifdef (_CASE1_) ... ... ... #elif (_CASE2_) ... ... ... #endif
现在在上面的例子中,如果您的应用程序需要_CASE1_
所涵盖的代码,那么您必须定义_CASE1_
。 例如#define _CASE1_
希望能帮助到你…
如果你正在研究一些开源项目,我认为你已经设置了它,以便你可以构建它。 选择一个包含您正在查找的宏的文件,并使用您的编译器生成预处理文件。 实际选项取决于你正在使用的编译器,它是-E for gcc,你可以在这里找到更多信息。
请注意,您可能必须使用项目的构建系统来实际编译文件,并查看预处理器运行所需的选项。
获得预处理文件后,只需搜索您的宏。 有预处理器选项可为每个包含的文件生成路径名。
更新:这种方法显然不起作用,因为您的宏由处理器扩展。 因此,除非您能够识别其扩展forms或其效果,否则它将毫无用处。
更有用的是让编译器打印出包含文件的确切顺序。 这是使用-H选项在gcc中实现的。
我通常会发现Vim足够了: CTRL-W CTRL-I
和[I
是我最喜欢的。 (这些是各种标识符, CTRL-W CTRL-D
和[D
仅用于宏。)您可以键入:help include-search
查看可用命令的完整列表。
要使这些工作正常,您应该在Vim中正确设置path
选项。 类型:set path?
查看您当前的设置。 运行gcc -v -E -x c++ - ,查找
#include <...> search starts here:
,并复制目录并将它们添加到path
(在.vimrc
)。 (我所做的是提取目录并将它们存储在.bash_profile
的环境变量中,并在我的.vimrc
引用它,如set path=$INCLUDE_PATH
。)您可能需要添加任何项目特定的包含目录到你的path
也是如此。
正如其他人所说,应该使用带有-d
选项之一的gcc
来找出定义宏的位置 。 这些选项不是由gcc -v --help
输出的,因此必须使用手册 3.11章节搜索-dCHARS
来读取它们。
最后我的步骤是:
- 使用
gcc ... -E -dD
- 在输出文件中找到定义
- 向后搜索
#
(散列和空格)以显示文件