Как получить адрес переменной, используя строку с именем переменной? - PullRequest
0 голосов
/ 29 октября 2009

Я хотел бы сделать что-то вроде простого и быстрого общего отладчика консоли. Эта небольшая библиотека должна быть встроена в основную программу.

Итак, я хотел бы сделать что-то подобное при запуске программы в режиме консоли:

«Ввод: печать я» «выход: 15,53» «Ввод: установить цвет 255» «вход: цвет печати» "выход: 255"

И «i», и «color» будут предварительно объявленными переменными в коде. Это не интерпретатор, просто удобный способ проверки и изменения содержимого переменных.

GDB не является правильным решением для моей проблемы, так как я буду использовать этот код для программ компьютерной графики, которые я буду кодировать, поэтому он должен быть в состоянии работать в «режиме выпуска».

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

Есть ли способ преобразовать строку, скажем, "color", чтобы получить адрес целочисленной переменной с именем color в C ++? Если нет, то как я могу решить эту проблему?

Ответы [ 11 ]

4 голосов
/ 29 октября 2009

Вы можете не знать об этой идиоме, которая может упростить вам реализацию этого:

#include <stdio.h>
#define REPORT(V) printf("%s: %i\n", #V, V);
int main() {
  int i = 5;
  REPORT(i);
  return 0;
}

Выход

i: 5
4 голосов
/ 29 октября 2009

Не для чутья сердца, но вы можете использовать dlopen и dlsym, чтобы получить адрес глобально объявленных переменных.

3 голосов
/ 29 октября 2009

Имена переменных предназначены для программиста, а C ++ не хранит метаданные. (Данные об исходном коде). Вы не можете получить доступ к переменной по имени во время выполнения.

Тем не менее, вы можете использовать что-то вроде std :: map или unordered_map (либо tr1 , либо boost ), что дает вам ключ и значение. Проблема в том, что значение должно быть однородным в контейнере. Это может быть облегчено с помощью Boost.Any .

2 голосов
/ 29 октября 2009

Нет, вы не можете этого сделать. После того, как вы скомпилируете исходный код в двоичную форму и удалите его из символов, в двоичном коде не будет записи понятных человеку имен.

Одним из вариантов в C ++ было бы использование std :: map из std :: string с любым типом данных ваших переменных. Затем вы можете обратиться к my_map["my_variable_name"] = new_value. Но это подразумевает незначительное влияние на производительность и в большинстве случаев не очень хорошая идея.

1 голос
/ 29 октября 2009

Вы можете использовать GDB с внешним файлом символов (команда symbol-file). Поэтому, если вы строите свой исполняемый файл с отладочной информацией во внешнем файле, вам даже не нужно писать собственный отладчик ... Просто не забудьте взять файл символов, когда вы отлаживаете установленный исполняемый файл клиента.

1 голос
/ 29 октября 2009
1 голос
/ 29 октября 2009

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

Я думаю, способ, которым вы упомянули (явно указав места, к которым вы хотите получить доступ из вашего «отладчика»), кажется, лучший путь. Вы можете использовать макросы как синтаксический сахар, чтобы немного облегчить бремя:

struct descriptor {
    const char* name;
    const char* type;
};

#define DEFGLOBAL(type, name) \
    static struct descriptor name ## _descriptor = { \
         # name, # type \
    }; \
    type name

DEFGLOBAL(int, some_number);

Я бы рекомендовал взглянуть на исходный код Emacs. Они делают что-то вроде вышеуказанных строк, чтобы экспортировать переменные C в интерпретатор Lisp. Они также используют его для экспорта примитивных функций и т. Д. На уровень Lisp.

0 голосов
/ 30 октября 2009

Что заставляет вас думать, что вы не можете запустить GDB в «режиме релиза»? Для идентификации переменных GDB использует символы отладки, и их можно создавать независимо от того, какие указаны другие флаги компилятора. Вы можете включить оптимизацию и все остальное, что составляет ваш «режим выпуска», и при этом генерировать символы отладки для использования GDB.

0 голосов
/ 30 октября 2009

Альтернативой для Lua было бы использование Boost :: Python; он также позволяет создавать API-интерфейсы сценариев quick-n-dirty.

0 голосов
/ 29 октября 2009

Простое решение, о котором вы подумали, по сути является единственным решением, доступным для неотладочного кода C / C ++. Тем не менее, я думаю, что есть два камня преткновения, которые вы должны рассмотреть:

  1. Вы сможете наблюдать только глобальные переменные. Любые локальные переменные в ваших функциях не будут доступны вашему инспектору, так как эти стековые фреймы не будут существовать, когда вы обрабатываете ввод из командной строки, предположительно, как часть цикла обработки верхнего уровня. (Если вы не обрабатываете ввод командной строки в каждой функции, что я бы не рекомендовал, и в этом случае вы никогда не узнаете, какой кадр стека функции будет проверяться при вводе команды.)
  2. Вы не позволите компилятору выполнить определенные оптимизации регистра. Если ваш код когда-либо берет адрес переменной (например, чтобы включить указатель на эту переменную в таблицу символов вашего инспектора), то компилятор должен поместить эту переменную в ячейку памяти, даже если в противном случае он будет хранить эту переменную исключительно в регистре для скорости.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...