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