Как найти источник некоторых макросов

Есть много мест для определения макроса. Когда макрос определен нами в нашем собственном проекте, нам легко найти позицию определения для них. Но когда я пытаюсь изучить какой-то известный проект с открытым исходным кодом, меня часто беспокоит вопрос: где найти источник макросов, если я не могу его определить, я не пойму некоторых из них (например, некоторые из них могут быть угаданы по их имени). например, некоторый оператор из apache:

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

#elif defined(__NSIG)

Что касается моих знаний, я знаю, что есть несколько возможных мест для макроса:

  • из этого самого проекта, в каком-то исходном файле (это проще всего, потому что мы можем найти его каким-то инструментом)
  • из некоторого заголовочного файла некоторой третьей библиотеки lib, мы можем grep его
  • из стандартного заголовочного файла c/С++ (где они находятся в Linux?)
  • из os (где они находятся в linux?)
  • автоматически генерируется инструментом configure (он горький, я понятия не имею)
  • из инструмента компилятора, такого как gcc/g++, или в make файле, мы можем определить макрос

У меня есть вопрос, чтобы проконсультироваться:

  • как различать их между определенными os и gcc/g++ и настраивать сгенерированные с помощью макроса инструменты? У них есть некоторые характеристики, соответственно?
  • как найти источник тех, которые определены os или стандартным C или компилятором? например, используя утилиты grep или find
  • что это означает, что нельзя найти один макрос, такой как __strange___, путем расчесывания всей машины (cd /;grep __strange___ -r)?

Спасибо, что рассказали принцип и метод, чтобы отличить их и, чтобы найти их источник!

Ответ 1

Простой, быстрый способ определить, где был определен макрос, - переопределить макрос и проверить сообщение компилятора "Предупреждение/ошибка".

#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

  • как различать их между определенными os и gcc/g++ и настраивать сгенерированные с помощью макроса инструменты? У них есть некоторые характеристики, соответственно?

Подавляющее большинство определяется где-то в каком-либо файле заголовка. gcc -dN -E может помочь. Предостережение: если вы используете этот подход, вам нужно вызвать gcc -dN -E с теми же путями include, теми же параметрами командной строки -D<name>, такими же переменными среды, как CPATH,..., как и при компиляции ваш источник в объектные файлы.

  • как найти источник тех, которые определены os или стандартным C или компилятором? например, используя утилиты grep или find

RTFM. Прочтите точное руководство.

  • что это означает, что если один макрос, такой как __strange__, не может быть найден, прочесывая всю машину (cd /;grep __strange___ -r)?

Это может означать, что этот символ не определен на вашем компьютере. Предположим, что этот код относится к некоторому пакету с открытым исходным кодом, который нацелен на лодку разных систем, разных компиляторов, некоторые из которых не совсем соответствуют стандарту С++. Типичный подход заключается в использовании #ifdef __some_bizarre_os__ в ключевых частях кода. Этот символ будет определен только на машинах под управлением Bizarre OS - не на вашем.

К сожалению, это не единственный случай. Символ может быть определен, даже если ваш grep не сможет найти его нигде. Makefile может объединить две строки, -D__str и ange__, чтобы сформировать один комманд командной строки для компилятора. Опция -D__strange__ может скрываться в простой видимости в одной из ваших переменных окружения, используемых в make файле. Файлы ~/.tcshrc, которые некоторые мандаты проектов могут быть невероятно запутаны.

Обновление
gcc -dM -E показывает определения макросов, но не там, где они были определены. Гораздо лучше использовать gcc -dN -E, а затем отфильтровывать строки, которые не начинаются с начального #.

Ответ 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

Ответ 4

Вы должны использовать IDE, например Eclipse, где вы можете просто щелкнуть правой кнопкой мыши макрос и нажать "Открыть объявление", и он отправит вас в файл и выберет макрос.

Иногда некоторые макросы даже не определены в файлах заголовков, поскольку они даются в качестве флагов компилятору gnu (например: -DMYMACRO).

Ответ 5

Если вы изучаете какой-то проект с открытым исходным кодом, я предполагаю, что вы его настроили, чтобы его можно было создать. Выберите один файл, содержащий макрос, который вы ищете, и используйте свой компилятор для создания предварительно обработанного файла. Фактический параметр зависит от используемого вами компилятора, его -E для gcc, вы можете найти дополнительную информацию здесь.

Обратите внимание, что вам, вероятно, придется использовать вашу систему построения проектов, чтобы фактически скомпилировать ваш файл и посмотреть, какие параметры вам нужны для успешного выполнения препроцессора.

Как только у вас есть предварительно обработанный файл, просто выполните поиск макроса. Существуют препроцессорные опции, которые генерируют путь для каждого включенного файла.

UPDATE: Этот подход явно не работает, потому что ваш макрос расширяется процессором. Таким образом, если вы не можете распознать его расширенную форму или ее эффекты, это будет мало пользы.

Что может быть несколько более полезным, так это заставить компилятор распечатать точную последовательность включенных файлов. Это достигается в gcc с опцией -H.

Ответ 6

Похоже, что эти макросы являются константами компиляции.

Хорошо использовать такие макросы, чтобы сообщить компилятору, что эта часть кода должна быть скомпилирована, и эта часть кода не должна компилироваться.

Если вы не можете искать их в рабочей области проекта, вам необходимо пройти через поток программы и решить, какая часть кода требуется для вашей аппликации и определить соответствующий макрос.

Например:

#ifdef (_CASE1_)

...
...
...

#elif (_CASE2_)

...
...
...

#endif

теперь в приведенном выше примере, если код, указанный в _CASE1_, требуется вашему приложению, вы должны определить _CASE1_. например #define _CASE1_

надеюсь, что это поможет...

Ответ 7

Я обычно нахожу 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, и ссылаться на это в моем .vimrc, как в set path=$INCLUDE_PATH.) Возможно, вам придется добавить любые каталоги включенных в проект конкретных включений ваш path.

Ответ 8

Как говорили другие, gcc с одним из параметров -d следует использовать для узнать, где макрос определен. Эти параметры не выводятся с помощью gcc -v --help, поэтому их необходимо прочитать с помощью руководства, главы 3.11, найдите -dCHARS.

Наконец, мои шаги:

  • Используйте gcc ... -E -dD
  • Найти определение в выходном файле
  • Искать назад для # (хэш и пробел), чтобы открыть файл