32

定义宏的地方很多,当我们在自己的项目中定义宏时,很容易找到它们的定义位置。但是当我尝试学习一些著名的开源项目时,我经常被一个问题所困扰:在哪里可以找到宏的来源,如果我无法得到它的定义,我将无法理解其中的一些(例如其中一些)可以通过他们的名字猜到)。例如,来自 apache 的一些声明:

#if defined(__osf__) && defined(__alpha),

#elif defined(__NSIG)

据我所知,我知道宏有一些可能的起源位置:

  1. 从这个项目本身,在一些源文件中(这是最简单的,因为我们可以通过一些工具找到它)
  2. 从一些第 3 个库的一些头文件中,我们可以 grep 它
  3. 来自 c/c++ 标准头文件(它们在 linux 中的什么位置?)
  4. 来自操作系统(它们在 linux 中的什么位置?)
  5. 由配置工具自动生成(很苦,我不知道)
  6. 从 gcc/g++ 之类的编译工具,或者在 makefile 中我们可以定义一些宏

我有一些问题要咨询:

  1. 如何区分 os 定义和 gcc/g++ 定义和配置工具生成的宏?它们各自有什么特点吗?
  2. 如何找到由 os 或标准 C 或编译器定义的源?例如,使用grepfind实用程序
  3. __strange___整机( ) 梳理找不到一个宏是什么意思cd /;grep __strange___ -r

感谢您告诉它们的原理和区分它们的方法,并找到它们的来源!

4

8 回答 8

54

找出宏在何处定义的一种简单、快速的方法是重新定义宏并检查编译器的警告/错误消息。

#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'
于 2015-05-07T10:51:22.937 回答
15
  1. 如何区分 os 定义和 gcc/g++ 定义和配置工具生成的宏?它们各自有什么特点吗?

绝大多数是在某个头文件中定义的。gcc -dN -E可以在这里提供帮助。警告:如果您使用这种方法,您需要gcc -dN -E使用相同的包含路径、相同的-D<name>命令行选项、相同的环境变量(例如CPATH,...)来调用,就像您将源文件编译为目标文件时所做的那样。

  1. 如何找到由 os 或标准 C 或编译器定义的源?例如,使用 grep 或查找实用程序

实时调频。阅读精美的手册。

  1. __strange__整机梳理找不到一个宏是什么意思(cd /;grep __strange___ -r)

这可能只是意味着您的计算机上没有定义该符号。假设有问题的代码来自某个开源包,该包针对大量不同系统、不同编译器,其中一些不太符合 C++ 标准。典型的做法是#ifdef __some_bizarre_os__在代码的关键部分使用。该符号只会在运行 Bizarre OS 的机器上定义 - 而不是在你的机器上。

不幸的是,这不是唯一的情况。即使您的 grep 无法在任何地方找到该符号,也可以很好地定义该符号。makefile 可以连接两个字符串,-D__strange__形成编译器的单个命令行参数。该选项-D__strange__可能隐藏在 makefile 使用的环境变量之一中。某些项目要求的 ~/.tcshrc 文件可能非常复杂。

更新
gcc -dM -E显示宏的定义,但不显示它们的定义位置。一个更好的选择是使用gcc -dN -E然后过滤掉不以首字母开头的行#

于 2012-06-29T11:02:25.910 回答
5

gcc 编译器定义的宏可以通过

gcc  -dM -E a.c

除此之外,它们都来自包含的文件和来源。

如果找不到宏,则意味着条件将被评估为假。

您还可以使用 -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
于 2012-06-29T07:18:27.923 回答
3

正如其他人所说,应该使用gcc其中一个选项来找出宏的定义位置。这些选项不是由 输出的,因此必须使用手册,第3.11章,搜索来阅读它们。-dgcc -v --help-dCHARS

最后我的步骤是:

  1. 利用gcc ... -E -dD
  2. 在输出文件中找到定义
  3. 向后搜索#(哈希和空格)以显示文件
于 2014-05-09T07:53:58.567 回答
2

看起来这些宏是编译常量。

使用这样的宏告诉编译器这部分代码需要编译,而这部分代码不需要编译,这是一个很好的做法。

如果您无法在项目工作区中搜索它们,那么您应该通过程序流程并确定您的应用程序需要哪一部分代码并定义相应的宏。

例如;

#ifdef (_CASE1_)

...
...
...

#elif (_CASE2_)

...
...
...

#endif

现在在上面的例子中,如果_CASE1_你的应用程序需要下面的代码,那么你必须定义_CASE1_. 例如#define _CASE1_

希望能帮助到你...

于 2012-06-29T07:45:52.500 回答
2

如果您正在研究一些开源项目,我假设您已经对其进行了设置,以便您可以构建它。选择一个包含您要查找的宏的文件,然后使用您的编译器生成一个预处理文件。实际选项取决于您使用的编译器,它是 gcc 的 -E,您可以在此处找到更多信息。

请注意,您可能必须使用项目的构建系统来实际编译文件并查看预处理器运行成功所需的选项。

一旦你有你的预处理文件,只需搜索你的宏。有一些预处理器选项可以为每个包含的文件生成路径名。

更新:这种方法显然不起作用,因为您的宏由处理器扩展。所以,除非你能认出它的扩展形式或效果,否则它几乎没有用处。

可能更有用的是让编译器打印出包含文件的确切顺序。这是在 gcc 中使用 -H 选项实现的。

于 2012-06-29T07:30:44.613 回答
0

我通常觉得 Vim 就足够了:CTRL-W CTRL-I而且[I是我的最爱。(这些是各种标识符,并且CTRL-W CTRL-D[D适用于宏。)您可以键入:help include-search可用命令的整个列表。

要使这些工作正常,您应该path正确设置 Vim 中的选项。键入:set path?以查看您的当前设置。运行gcc -v -E -x c++ - </dev/null、查找#include <...> search starts here:并复制目录并将它们添加到您的path(在您的.vimrc)中。(我所做的是提取目录并将它们存储到 中的环境变量中.bash_profile,并在 my 中引用它.vimrc,如 中set path=$INCLUDE_PATH。)您可能还需要将任何特定于项目的包含目录添加到您的目录中path

于 2013-04-25T17:59:15.087 回答
0

您应该使用像 Eclipse 这样的 IDE,您可以在其中简单地右键单击宏并单击打开声明,它会将您发送到文件并定义宏。

有时某些宏甚至没有在头文件中定义,因为它们作为标志提供给 gnu 编译器(例如:-DMYMACRO)。

于 2012-06-29T07:29:55.190 回答