在C程序中是否可以在运行时知道函数参数和变量的名称类型?例如,如果我有一个函数:
int abc(int x, float y , somestruct z ){
char a;
int b ;
}
我可以在这个函数abc()
中知道,参数和变量的名称是什么即在这种情况下是x
,y
,{{1 }},z
,a
,它们的类型为b
,int
,float
,somestruct
,char
。< / p>
说是否还有其他功能:
int
我应该知道参数名称是float some_func(specialstruct my_struct, int index){
}
,my_struct
,类型是index
,specialstruct
。
我在运行时需要这些信息吗?
我可以访问基指针和返回地址,我可以使用上面的指针获取所需的信息。
我能够使用返回地址和int
函数提取函数名称。
我看到dladdr()
这样做了,所以应该可以提取这些信息吗?
答案 0 :(得分:1)
C中没有任何反射或类似的东西。如果你想要这样的设施 - 你应该为此目的设计一些实用程序,宏,并使用特殊的编码规则来达到预期的效果。但IMO - 它不是一个可读且易于理解的C代码。
答案 1 :(得分:1)
在C中实现这一点并不是真正的本地方式。在其他语言中,你要寻找的就是反思。你可以用宏和一些技巧来干酪,但是基于一个基本原则,你需要在编译时知道变量名和参数。
答案 2 :(得分:0)
共享库函数dlsym
和dladdr
提供了一种有限的内省方式,提供了一个名称到地址,反之亦然。但是,这不是C语言的一部分,而是OS动态加载程序提供的功能。但是,您不能扣除,例如,您找到的符号是变量还是函数。
backtrace
等构成了标准的GNU扩展,允许分析函数的调用堆栈(调用历史)。如果二进制文件中仍然存在符号(函数名称),backtrace_symbols
将允许您检索它们。
__LINE__
和__FILE__
预定义宏提供了一种转储方式,也可以作为一些非常有用的跟踪宏的基础。
就是这样。 C不提供任何更多的内省。参数名称和类型在二进制文件中消失,函数签名也消失了,函数结果类型也消失了。
答案 3 :(得分:0)
正如其他人所说,反射不是内置于C或C ++语言中。有各种各样的想法here
但是,可以在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&#39;与争论x,y和z。
参数x的类型是与键0x4e的类型表的间接。
在输出的其他地方,我们可以看到类型0x4e的定义。类型0x2d是连接到参数z的somestruct。
< 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功能。
我使用此策略的变体来创建自定义调试器和内存泄漏检测器。我从未见过这种用于业务逻辑的策略。