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

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

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

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

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

float some_func(specialstruct my_struct, int index){

} 

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

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

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

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

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

4 ответа

Как уже отмечалось, рефлексия не встроена в язык 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 считывать статическую и динамическую информацию для процесса. Другой процесс может использовать аналогичные функции для создания функций отражения.

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

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

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

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

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

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

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

Другие вопросы по тегам