имя переменной, аргументы функции во время выполнения в C

Можно ли узнать типы имен аргументов и переменных функции во время выполнения в программе на C? Например, если у меня есть функция:

int abc(int x, float y , somestruct z ){
    char a;
    int b ;
}

Могу ли я узнать внутри этой функции abc(), как называются аргументы и переменные ie, в данном случае это x, y, z, a, b, и они относятся к типу int, float, somestruct, char, int.

Скажите, есть ли еще одна функция:

float some_func(specialstruct my_struct, int index){

} 

Я должен знать, что имена аргументов my_struct, index, а типы specialstruct, int.

Мне нужна эта информация во время выполнения?

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

Мне удалось извлечь имя функции, используя адрес возврата и функцию dladdr().

Я вижу, GDB делает это, значит, можно ли извлечь эту информацию?


person app    schedule 15.09.2016    source источник
comment
Зачем вам нужны эти имена во время выполнения? Что ты мог с ними сделать?   -  person Mat    schedule 15.09.2016
comment
C - это компилируемый язык. После компиляции программы (или, другими словами, после ее преобразования в машинный код) все имена переменных, имена функций и т. Д. Исчезают. Итак, ответ: Нет. С другой стороны, GDB знает об именах переменных и функций, потому что программа была скомпилирована со специальными параметрами, но это полезно только для отладки.   -  person Jabberwocky    schedule 15.09.2016
comment
gdb использовать отладочную информацию, созданную компилятором. См. eli.thegreenplace.net/ 2011/02/07 /   -  person Mathieu    schedule 15.09.2016
comment
@MichaelWalz: Скомпилировано или нет - не проблема. Скомпилированный язык также может возвращать атрибуты к самому коду. Отражение было частью С ++ 17, но, насколько мне известно, оно удалено. Другие языки имеют эту функцию.   -  person Klaus    schedule 15.09.2016
comment
@Klaus правильный, но нет никакого отражения, что и когда-либо в C.   -  person Jabberwocky    schedule 15.09.2016
comment
Возможный дубликат Программного способа получить имя переменной в C?   -  person Raman    schedule 15.09.2016
comment
Нет. Типы (в общем случае) не являются частью выполнения программы во время выполнения. Типы существуют только на языке, то есть в том, что описывает программу. Программа на C обычно не знает своего собственного описания (если вы явно не указали это).   -  person Kerrek SB    schedule 15.09.2016
comment
@Mat, Допустим, условие assert истинно, но я не хочу останавливать выполнение, поэтому я хочу сбросить свой стек вызовов вместе с аргументом и именем переменной вместе со значениями.   -  person app    schedule 16.09.2016
comment
Отредактируйте это в своем вопросе (должно быть там с самого начала). Нет портативных способов получить это. Точный дамп переменной для оптимизированного дампа является проблемой. невозможно.   -  person Mat    schedule 16.09.2016


Ответы (4)


В C. нет никакого отражения или подобных вещей. Если вам нужна такая возможность - вы должны разработать для этого какие-то утилиты, макросы и использовать специальные правила кодирования для достижения желаемого эффекта. Но ИМО - это не будет читаемый и понятный код C.

person Sergio    schedule 15.09.2016

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

person magisch    schedule 15.09.2016
comment
@Mat Похоже, я там пошутил. Я имел в виду аргументы, с которыми запускается программа. Исправление. - person magisch; 15.09.2016

Как отмечали другие, отражение не встроено в язык C или C ++. здесь есть множество идей.

Однако отражение возможно в C / C ++ со сторонней библиотекой и отладочными символами в исполняемом или внешнем файле.

Исполняемый файл dwarfdump более или менее делает то, на что вы надеетесь. В DWARF доступна подробная информация о функциях, переменных, типах и т. Д. Подобным образом функциональность libdwarfdump может использоваться процессом для проверки самого себя.

Вот простой ручной пример:

typedef struct somestruct 
{
   int i;
   int j;
} somestruct ;

int abc(int x, float y , struct somestruct z ){
    char a;
    int b ;
}


int main(int argc, char* argv[])
{

   struct somestruct z;
   abc(1,1.0f,z);
   return 0;
}

и частичный вывод dwarfdump

< 1><0x00000055>    DW_TAG_subprogram
                      DW_AT_external              yes(1)
                      DW_AT_name                  "abc"
                      DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                      DW_AT_decl_line             0x00000009
                      DW_AT_prototyped            yes(1)
                      DW_AT_type                  <0x0000004e>
                      DW_AT_low_pc                0x004004ed
                      DW_AT_high_pc               <offset-from-lowpc>18
                      DW_AT_frame_base            len 0x0001: 9c: DW_OP_call_frame_cfa
                      DW_AT_GNU_all_call_sites    yes(1)
                      DW_AT_sibling               <0x000000ad>
< 2><0x00000076>      DW_TAG_formal_parameter
                        DW_AT_name                  "x"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x0000004e>
                        DW_AT_location              len 0x0002: 916c: DW_OP_fbreg -20
< 2><0x00000082>      DW_TAG_formal_parameter
                        DW_AT_name                  "y"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x000000ad>
                        DW_AT_location              len 0x0002: 9168: DW_OP_fbreg -24
< 2><0x0000008e>      DW_TAG_formal_parameter
                        DW_AT_name                  "z"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x0000002d>
                        DW_AT_location              len 0x0002: 9160:        DW_OP_fbreg -32

При внимательном изучении мы видим, что фрагмент определяет функцию abc с аргументами x, y и z.

Тип параметра x - это косвенное обращение к таблице типов с ключом 0x4e.

В другом месте вывода можно увидеть определение типа 0x4e. Тип 0x2d - это некоторая структура, которая связана с параметром z.

< 1><0x0000002d>    DW_TAG_structure_type
                      DW_AT_name                  "somestruct"
                      DW_AT_byte_size             0x00000008
                      DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                      DW_AT_decl_line             0x00000003
                      DW_AT_sibling               <0x0000004e>

< 1><0x0000004e>    DW_TAG_base_type
                      DW_AT_byte_size             0x00000004
                      DW_AT_encoding              DW_ATE_signed
                      DW_AT_name                  "int"

Комбинация ptrace, ELF, DWARF и файловой системы / proc позволяет gdb читать статическую и динамическую информацию о процессе. Другой процесс может использовать аналогичную функциональность для создания функциональности Reflection.

Я использовал варианты этой стратегии для создания собственных отладчиков и детекторов утечки памяти. Однако я никогда не видел, чтобы эта стратегия использовалась для бизнес-логики.

person Matthew Fisher    schedule 15.09.2016

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

backtrace и другие создают расширение GNU к стандарту, которое позволяет анализировать стек вызовов функции (историю вызовов). Если в двоичном файле все еще присутствуют символы (имена функций), backtrace_symbols позволит вам их получить.

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

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

person tofro    schedule 15.09.2016