Подтвердить что ты не робот

Программный способ получить имя переменной в C?

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

Мое решение: Сохраните имя переменной в виде строки и напечатайте "имя переменной", а затем ее значение.

Есть ли какой-либо программный способ узнать имя переменной?

4b9b3361

Ответ 1

Вы можете попробовать что-то вроде этого:

#define DUMP(varname) fprintf(stderr, "%s = %x", #varname, varname);

Я использовал этот заголовок. Я написал, когда был знаком с C, он мог бы содержать некоторые полезные идеи. Например, это позволит вам распечатать значение C и предоставить спецификатор формата в одной (а также некоторую дополнительную информацию):

#define TRACE(fmt, var) \
        (error_at_line(0, 0, __FILE__, __LINE__, "%s : " fmt, #var, var))

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

Ответ 2

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

Ответ 3

На самом деле у меня есть код, который может делать то, что вы хотите. Он использует препроцессор для форматирования имени переменной, чтобы вы могли распечатать его. Он сбрасывает имя переменной и значение (на основе типа) и макет памяти для этой переменной. Следующая программа показывает, как это делается:

#include <stdio.h>
#include <stdlib.h>

static void dumpMem (unsigned char *p, unsigned int s) {
    int i;
    unsigned char c[0x10];
    printf (">>      ");
    for (i = 0; i < 0x10; i++) printf (" +%x",i);
    printf (" +");
    for (i = 0; i < 0x10; i++) printf ("%x",i);
    printf ("\n");
    for (i = 0; i < ((s + 15) & 0xfff0); i++) {
        if ((i % 0x10) == 0) {
            if (i != 0) printf ("  %*.*s\n", 0x10, 0x10, c);
            printf (">> %04x ",i);
        }
        if (i < s) {
            printf (" %02x", p[i]);
            c[i & 0xf] = ((p[i] < 0x20) || (p[i] > 0x7e)) ? '.' : p[i];
        } else {
            printf ("   ");
            c[i & 0xf] = ' ';
        }
    }
    printf ("  %*.*s\n", 0x10, 0x10, c);
}
#define DUMPINT(x) do{printf("%s: %d\n",#x,x);dumpMem((char*)(&x),sizeof(int));}while(0)
#define DUMPSTR(x) do{printf("%s: %s\n",#x,x);dumpMem(x,strlen(x));}while(0)
#define DUMPMEM(x,s) do{printf("%s:\n",#x);dumpMem((char*)(&x),s);}while(0)

typedef struct {
    char c;
    int i;
    char c2[6];
} tStruct;

int main (void) {
    int i = 42;
    char *s = "Hello there, my name is Pax!";
    tStruct z;
    z.c = 'a'; z.i = 42; strcpy (z.c2,"Hello");

    DUMPINT (i);
    DUMPSTR (s);
    DUMPMEM (z,sizeof(z));

    return 0;
}

Выводится:

i: 42
>>       +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000  2a 00 00 00                                      *...
s: Hello there, my name is Pax!
>>       +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000  48 65 6c 6c 6f 20 74 68 65 72 65 2c 20 6d 79 20  Hello there, my
>> 0010  6e 61 6d 65 20 69 73 20 50 61 78 21              name is Pax!
z:
>>       +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000  61 b6 16 61 2a 00 00 00 48 65 6c 6c 6f 00 0d 61  a..a*...Hello..a

И если вы задаетесь вопросом о здравомыслии do {...} while (0) в макросах, чтобы включить его в любом месте в коде, не беспокоясь о том, есть ли у вас достаточные скобки вокруг него.

Ответ 4

Если вам нужно сделать это для произвольных переменных, вам, вероятно, понадобится использовать API-интерфейс отладчика, который предоставляет компилятор или платформа (например, DbgHelp в Windows).

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

typedef 
struct vartab {
    char const* name;
    int * var;
} vartab;


vartab varTable[] = {
    { "foo", &foo },
    { "bar", &bar }
};

Затем я просто использовал небольшую процедуру, которая ищет таблицу для рассматриваемого имени переменной и выгружает имя и данные, на которые указывает указатель. Если вам нужно сбросить данные, отличные от простых int, вы можете расширить структуру, чтобы также сохранить форматировщик формата printf и изменить указатель на void* и передать этот мусор на snprintf() или что-то в формате данных.

Иногда я также использую макрос, который помогает построить таблицу (возможно, также объявив переменную). Но, честно говоря, я думаю, что это действительно просто усложняет понимание (особенно для кого-то нового присоединения к проекту - у них часто бывает небольшой "WTF?" ) И на самом деле это не очень упрощает.

Ответ 5

Люди часто хотят, чтобы программы самонастраивались (или "отразились" на текущем жаргоне). Но большинство языков программирования предлагают небольшую (например, Java) или никому (C) возможность отражать все детали программы (имена переменных, имена функций, типы, структуры выражений и т.д.).

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

См. этот ответ SO для обсуждения того, как "получить имена переменных" и распечатать значения с помощью системы преобразования программ: Автоматически отслеживать изменения переменных

Ответ 6

Более короткий путь:

#define GET_VARIABLE_NAME(Variable) (#Variable)

Тест:

#include <string>
class MyClass {};


int main(int argc, char* argv[]) {
    int foo = 0;

    std::string var_name1 = GET_VARIABLE_NAME(foo);
     char* var_name2 = GET_VARIABLE_NAME(foo);
     char* var_name3 = GET_VARIABLE_NAME(MyClass);


    return 0;
}

Ответ 7

Если ваш исполняемый файл скомпилирован с информацией об отладке, вы можете получить эту информацию. Если нет, вам, вероятно, не повезло. Итак, вы строите отладчик? Зачем? Существующие отладчики для c очень зрелые. Почему бы не использовать существующие инструменты вместо того, чтобы повторно изобретать колесо?

Ответ 8

Невозможно сделать это изнутри вашей программы, я боюсь (кроме ответа Anacrolix). Я считаю, что правильным решением вашей проблемы является отладчик script. В большинстве отладчиков вы можете даже подключить его к запуску каждый раз, когда отладчик прерывает выполнение программы (точка останова, вы нажимаете ^C и т.д.) И получаете моментальный снимок состояния своей программы каждый раз, когда вы взаимодействуете с ним.

Ответ 9

Попробуйте это.

#define MACRO_VARIABLE_TO_STRING(Variable) ((void) Variable,#Variable)

Код (void) Переменная - это пустое преобразование, которое не является оператором, тогда есть оператор запятой и макрос. Таким образом, чистый результат const char *, содержащий имя переменной с проверкой компилятора, действительно существует переменная.

Теперь у вас есть имя вашей переменной, и вы можете использовать printf() для печати своего значения.