如何找到一些宏的来源

时间:2012-06-29 07:03:46

标签: c++ c macros

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

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

#elif defined(__NSIG)

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

  1. 来自这个项目本身,在一些源文件中(这是最简单的,因为我们可以通过某种工具找到它)
  2. 从某些第三个lib的头文件,我们可以grep它
  3. 来自c / c ++标准头文件(他们在linux中的位置?)
  4. 来自os的
  5. (他们在Linux中的位置?)
  6. 由配置工具自动生成(它很苦,我不知道)
  7. 来自编译器工具,如gcc / g ++,或者在makefile中我们可以定义一些宏
  8. 我有一些问题需要咨询:

    1. 如何区分os定义的和定义的gcc / g ++并配置工具生成的宏?它们分别具有一些特征吗?
    2. 如何找到os或标准C或编译器定义的源代码?例如,使用grepfind实用程序
    3. 如果通过梳理整个机器(__strange___)无法找到cd /;grep __strange___ -r这样的宏,这意味着什么?
    4. 感谢您告诉原则和方法来区分它们,并找到它们的来源!

8 个答案:

答案 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)

  
      
  1. 如何区分os定义的和定义的gcc / g ++并配置工具生成的宏?它们分别具有一些特征吗?
  2.   

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

  
      
  1. 如何找到os或标准C或编译器定义的源代码?例如,使用grep或find utilities
  2.   

RTFM。阅读精细手册。

  
      
  1. 如果通过梳理整个机器__strange__无法找到(cd /;grep __strange___ -r)这样的宏,这意味着什么?
  2.   

这可能只是意味着您的计算机上未定义该符号。假设有问题的代码来自一些开源软件包,它针对不同系统,不同编译器,其中一些不完全符合C ++标准。典型的方法是在代码的关键部分使用#ifdef __some_bizarre_os__。该符号仅在运行Bizarre OS的计算机上定义 - 而不是在您的计算机上定义。

不幸的是,这不是唯一的情况。即使您的grep无法在任何地方找到它,也可能会定义符号。 makefile可以连接两个字符串-D__strange__,以形成编译器的单个命令行参数。选项-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

最后我的步骤是:

  1. 使用gcc ... -E -dD
  2. 在输出文件中找到定义
  3. 向后搜索#(哈希和空格)以显示文件