6

是否可以在 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){

} 

我应该知道参数名称是my_struct,index类型是specialstruct, int

我在运行时需要这些信息吗?

我可以访问基指针和返回地址,我可以使用上面的指针获取所需的信息。

我能够使用返回地址和dladdr()函数来提取函数名。

我看到GDB了,所以应该可以提取此信息?

4

4 回答 4

1

在 C 中并没有真正的本地方式来执行此操作。在其他语言中,您要寻找的是反射。您可以使用宏和一些技巧来解决它,但在基本原则上,您需要在编译时知道变量名称和参数。

于 2016-09-15T08:35:12.507 回答
1

正如其他人所指出的,反射并未内置于 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 相关联的 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 读取进程的静态和动态信息。另一个进程可以使用类似的功能来创建反射功能。

我已使用此策略的变体来创建自定义调试器和内存泄漏检测器。但是,我从未见过将这种策略用于业务逻辑。

于 2016-09-15T14:21:51.617 回答
1

C中没有反射或类似的东西。如果你想要这样的设施 - 你应该为此目的设计一些实用程序,宏并使用特殊的编码规则来达到预期的效果。但是 IMO - 它不会是可读和可理解的 C 代码。

于 2016-09-15T08:22:47.213 回答
0

共享库函数提供了一种有限的自省方式,dlsymdladdr提供名称到地址的转换,反之亦然。然而,这不是 C 语言的一部分,而是 OS 动态加载程序提供的一个函数。但是,您不能推断,例如,您找到的符号是变量还是函数。

backtrace等人构成了标准的 GNU 扩展,允许分析函数的调用堆栈(调用历史)。如果二进制文件中仍然存在符号(函数名称),backtrace_symbols将允许您检索它们。

__LINE__和预定义的__FILE__宏也提供了一种转储您所在位置的方法,并且可以成为一些非常有用的跟踪宏的基础。

就是这样。C 没有提供比这更多的内省。参数名称和类型在二进制文件中消失了,函数签名和函数结果类型也消失了。

于 2016-09-15T09:15:31.673 回答