如何找到某些宏的来源
how to find the source of some macros
地方可以定义宏。当我们在自己的项目中定义宏时,很容易找到它们的定义位置。但是当我尝试学习一些著名的开源项目时,我经常被一个问题所困扰:在哪里可以找到宏的来源,如果我不能得到它的定义,我就不会理解其中的一些(例如,其中一些可以通过它们的名字来猜测)。例如,来自 Apache 的一些声明:
#if defined(__osf__) && defined(__alpha),
#elif defined(__NSIG)
至于我的知识,我知道宏有一些可能的起源地:
- 从这个项目本身,在一些源文件中(这是最简单的,因为我们可以通过一些工具找到它)
- 从某个 3rd lib 的一些头文件中,我们可以 grep 它
- 从C/C ++标准头文件(它们在Linux中的什么位置?
- 从操作系统(它们在Linux中在哪里?
- 由配置工具自动生成(很苦,我不知道)
- 从像 gcc/g++ 这样的编译器工具中,或者在 makefile 中我们可以定义一些宏
我有一些问题要咨询:
- 如何区分操作系统定义的和 GCC/G++ 定义的以及配置工具生成的宏? 它们分别具有一些特征吗?
- 如何找到操作系统或标准C或编译器定义的源代码? 例如,使用
grep
或find
实用程序 - 如果通过梳理整个机器(
cd /;grep __strange___ -r
)找不到一个宏,例如__strange___
,这意味着什么?
感谢您告诉区分它们的原理和方法,并找到它们的来源!
找出宏定义位置的一种简单、快速的方法是重新定义宏并检查编译器的警告/错误消息。
#include <windows.h>
#define min(a,b) nonsense
mintest.cpp(3) : warning C4005: 'min' : macro redefinition
C:ProgrammeMicrosoft SDKsWindowsv6.0Aincludewindef.h(194) : see previous definition of 'min'
- 如何区分操作系统定义的和 GCC/G++ 定义的以及配置工具生成的宏? 它们分别具有一些特征吗?
绝大多数是在某个头文件中定义的。 gcc -dN -E
在这里可以提供帮助。警告:如果使用此方法,则需要使用相同的包含路径、相同的-D<name>
命令行选项、相同的环境变量(如 CPATH
、...)调用gcc -dN -E
,就像将源文件编译为对象文件时所做的那样。
- 如何找到由操作系统或标准C或编译器定义的源代码? 例如,使用 grep 或查找实用程序
RTFM。阅读精细手册。
- 如果通过梳理整个机器
(cd /;grep __strange___ -r)
找不到一个宏(例如__strange__
)是什么意思?
这可能只是意味着您的计算机上未定义该符号。假设有问题的代码来自某个开源包,该包针对不同系统、不同编译器的大量内容,其中一些不太符合C++标准。典型的方法是在代码的关键部分使用 #ifdef __some_bizarre_os__
。该符号只会在运行Bizarre OS的机器上定义 - 而不是在你的机器上。
不幸的是,这不是唯一的情况。即使您的 grep 在任何地方都找不到它,也可以很好地定义该符号。makefile 可以连接两个字符串(-D__str
和 ange__
,以形成编译器的单个命令行参数。选项-D__strange__
可能隐藏在生成文件使用的环境变量之一中。某些项目授权的~/.tcshrc文件可能非常复杂。
更新
gcc -dM -E
显示了宏的定义,但没有显示宏的定义位置。更好的选择是使用 gcc -dN -E
,然后过滤掉不以初始#
开头的行。
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
正如其他人所说,应该使用具有-d
选项之一的gcc
来找出宏的定义位置。这些选项不是由gcc -v --help
输出的,因此必须使用手册第 3.11 章 搜索-dCHARS
来阅读它们。
最后我的步骤是:
- 使用
gcc ... -E -dD
- 在输出文件中查找定义
- 向后搜索
#
(哈希和空格)以显示文件
看起来这些宏是编译常量。
最好使用此类宏告诉编译器这部分代码需要编译,而这部分代码不进行编译。
如果您无法在项目工作区中搜索它们,则应浏览程序流程,并确定应用程序需要哪一部分代码,并定义相应的宏。
例如;
#ifdef (_CASE1_)
...
...
...
#elif (_CASE2_)
...
...
...
#endif
现在在上面的例子中,如果你的应用程序需要_CASE1_
涵盖的代码,那么你必须定义_CASE1_
,例如 #define _CASE1_
希望对...
如果你正在研究一些开源项目,我假设你已经设置好了它,以便你可以构建它。选择一个包含要查找的宏的文件,并使用编译器生成预处理的文件。实际选项取决于您使用的编译器,它是 -E 表示 gcc,您可以在此处找到更多信息。
请注意,您可能必须使用项目的生成系统来实际编译文件,并查看预处理器运行成功所需的选项。
获得预处理文件后,只需搜索宏即可。有一些预处理器选项可以为每个包含的文件生成路径名。
更新:这种方法显然不起作用,因为您的宏是由处理器扩展的。因此,除非你能认识到它的扩展形式或效果,否则它几乎没有用处。
可能更有用的是让编译器打印出包含文件的确切顺序。这是在 gcc 中使用 -H 选项实现的。
您应该使用像 Eclipse 这样的 IDE,您只需右键单击宏并单击"打开声明",它就会将您发送到文件并行定义的宏。
有时有些宏甚至没有在头文件中定义,因为它们是作为 gnu 编译器的标志给出的(例如:-DMYMACRO)。
我通常觉得 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
中。
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 如何找出GDB的SIGTRAP核心转储的根本原因
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 找不到QtResource文件中的文件
- Python中的for循环与C++有何不同
- VC++本机单元测试,找不到调试符号
- RegGetValue在当前用户下找不到名称
- 带有 -stdlib=libc++ 的 clang++ 9.0.1 找不到<optional>
- c++找不到具有相同哈希的无序集合元素
- 找不到以下加速库:boost_fiber
- 找不到 FLTK(缺少:FLTK_INCLUDE_DIR)
- 设置 Visual Studio for MPI: 找不到标识符错误
- "assimp/config.h"找不到,但它在文件夹中
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- C++系统找不到指定的文件错误
- FindPackageHandleStandardArgs.cmake:137 的 CMake 错误(消息):找不到 Boost (缺少:正则表达式)(找到合适的版本"1.72.0",