how to find the source of some macros

2019-02-01 23:01发布

问题:

There are many places for defining a macro.When the macro is defined in our own project by us,the are easy to find the definition position for them. But when i try to learn some famous open source project,i am frequently pestered by the question:where to find the source of the macros,if i can not get it's definition,i won't understand some of them (e.g. some of them can be guessed by their name). for example,some statement from apache:

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

#elif defined(__NSIG)

as for my knowledge,i know there are some possible originating place for a macro:

  1. from this project itself,in some source file(this is the easiest,because we can find it by some tool)
  2. from some header file of some 3rd lib ,we can grep it
  3. from c/c++ standard header file(where are they in linux?)
  4. from the os (where are they in linux?)
  5. automatically generated by the configure tool(it is bitter,i have no idea)
  6. from the compiler tool like gcc/g++,or in the makefile we can define some macro

I have some question to consult:

  1. how to differentiate them between os defined and gcc/g++ defined and configure tool generated macros? do they have some characteristic respectively?
  2. how to find the source of those defined by os or by standard C or compiler? e.g.,using grep or find utilities
  3. what does it mean if one macro such as __strange___ can not be find by combing the whole machine (cd /;grep __strange___ -r)?

Thanks for telling the principle and the method to distinguish them and ,to find the source of them!

回答1:

A simple, quick way to find out where a macro has been defined is to redefine the macro and check compiler's Warning/Error message.

#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'


回答2:

  1. how to differentiate them between os defined and gcc/g++ defined and configure tool generated macros? do they have some characteristic respectively?

The vast majority are defined in some header file somewhere. gcc -dN -E can be of help here. Caveat: If you use this approach, you need to invoke gcc -dN -E with the same include paths, the same -D<name> command line options, the same environment variables such as CPATH, ..., as you do when you compile your source to object files.

  1. how to find the source of those defined by os or by standard C or compiler? e.g.,using grep or find utilities

RTFM. Read the fine manual.

  1. what does it mean if one macro such as __strange__ can not be find by combing the whole machine (cd /;grep __strange___ -r)?

It could just mean that that symbol isn't defined on your computer. Suppose the code in question is from some open source package that targets a boatload of different systems, different compilers, some of which are not quite compliant with the C++ standard. The typical approach is to use #ifdef __some_bizarre_os__ in key parts of the code. That symbol will only be defined on machines running the Bizarre OS -- not on yours.

Unfortunately, that's not the only case. The symbol might well be defined even if your grep can't find it anywhere. The makefile could concatenate two strings, -D__str and ange__ to form a single command line argument to the compiler. The option -D__strange__ might be hiding in plain sight in one of your environment variables used by the makefile. The ~/.tcshrc files that some projects mandate can be incredibly convoluted.

Update
gcc -dM -E shows the definitions of the macros, but not where they were defined. A much better options is to use gcc -dN -E and then filter out lines that don't start with an initial #.



回答3:

gcc compiler defined macros can be revealed by

gcc  -dM -E a.c

Other than that, they all come from included files and sources.

If you can't find the macro, that means the conditional will be evaluated to false.

You can also use the -v option, it reveal where it finds its default include directories.

To find out which file the macro is from:

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


回答4:

You should use a IDE like Eclipse where you can simply right click on the macro and click Open Declaration and it will send you to the file and line the macro is defined.

Sometimes some macros aren't even defined in the header files as they are given as flags to the gnu compiler (example: -DMYMACRO).



回答5:

It looks like these macros are compilation constants.

It is good practice to use such macros to tell compiler that this part of code need to be compiled and this part of code is not to be compiled.

If you are not able to search them in your project workspace then you should go through the program flow and decide which part of code is required by your appication and define the respective macro.

For example;

#ifdef (_CASE1_)

...
...
...

#elif (_CASE2_)

...
...
...

#endif

now in above example, if the code covered under _CASE1_ is required by your application then you must define _CASE1_. e.g. #define _CASE1_

hope it helps...



回答6:

If you're studying some open source project I assume that you have set it up so that you can build it. Choose one file that contains the macro you're looking for and use your compiler to generate a preprocessed file. The actual option depends on the compiler you're using, it's -E for gcc, you can find some more information here.

Note that you'll probably have to use your project's build system to actually compile your file and see which options you need for the preprocessor run to succeed.

Once you have your preprocessed file, just search for your macro. There are preprocessor options that generate the pathname for each included file.

UPDATE: This approach obviously doesn't work, because your macro is expanded by the processor. So, unless you can recognize its expanded form or its effects, it would be of little use.

What could be somewhat more useful is to get the compiler to print out the exact sequence of included files. This is achieved in gcc with the -H option.



回答7:

I usually find Vim enough for this: CTRL-W CTRL-I and [I are my favourite. (These are all kinds of identifiers, and CTRL-W CTRL-D and [D are for macros only.) You can type :help include-search for the whole list of the available commands.

For these to work, you should have your path option in Vim set up correctly. Type :set path? to see your current setting. Run gcc -v -E -x c++ - </dev/null, look for #include <...> search starts here:, and copy the directories and add them to your path (in your .vimrc). (What I do is to extract the directories and store them into an environment variable in .bash_profile, and refer to that in my .vimrc, as in set path=$INCLUDE_PATH.) You may need to add any project-specific include directories to your path as well.



回答8:

As others said, gcc with one of -d options should be used to find out where the macro is defined. Those options are not outputted by gcc -v --help, so they must be read using the manual, chapter 3.11, search for -dCHARS.

Finally my steps are:

  1. Use gcc ... -E -dD
  2. Find the definition in the output file
  3. Search backwards for # (a hash and a space) to reveal the file


标签: c++ c macros