2009-10-26 3 views
28

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

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

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

ответ

47

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

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

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

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

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

+0

Это хорошая идея делать что-то изнутри программы. Создает кучу строковых констант, это точно. –

+0

Возможно, вам лучше определить его как 'DUMP (varname, format)' и использовать ''% s = "format" \ n "' в 'fprintf', позволяя ему работать с большим количеством типов:' DUMP (somestring, "% s") 'или' DUMP (someint, "% d") '. – caf

+0

Это обычный способ неинтроскопической природы c. Как вы можете себе представить, у нее есть свои пределы и ловушки, но это примерно так же хорошо, как вы можете сделать, не создавая собственного интроспективного переводчика. – dmckee

1

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

+0

некоторые примеры допрашивать отладчика во время выполнения, пожалуйста? –

11

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

1

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

4

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

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

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


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

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

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

6

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

#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 +fabcdef 
>> 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 +fabcdef 
>> 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 +fabcdef 
>> 0000 61 b6 16 61 2a 00 00 00 48 65 6c 6c 6f 00 0d 61 a..a*...Hello..a 

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

3

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

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

Посмотрите этот SO ответа для обсуждения того, как «получить имена переменных» и значение печати с помощью системы трансформации программы: Trace changes to variables automatically

0

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

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

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

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

3

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

#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; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^