取消引用指向具有未知类型的变量的指针

时间:2012-09-17 20:17:15

标签: c++ c memory

我不知道如何解释我现在遇到的问题,如果我对问题的标题含糊不清,那就很抱歉。

我现在所拥有的是存储在变量中的虚拟地址列表。例如,我有

  

0x8c334dd

存储在char变量中。该地址是另一个包含数据的变量的地址。我想要做的是转到该地址并获取存储在其上的数据。

我的假设是取消引用指针本来是最好的方法,遗憾的是我不知道地址指向的变量的类型,那么解除引用在这种情况下如何工作?我不能这样做:*(char *) 8c334dd因为我不知道地址所指向的变量的类型......

如果我将其转换为(int *),我会得到一些地址所指向的某些变量的数据(请记住我有几个地址)但是对于其他人我只是得到一个地址,我需要数据(这个变量是结构,字符等)。

我正在使用ELF符号表

2 个答案:

答案 0 :(得分:3)

通常,C ++或C无法知道你的指针类型。

解决此问题的常用方法是使指针指向结构,并在结构中具有已知位置以指示数据的类型。通常,已知位置是结构中的第一个位置。

示例:

// signature value; use any value unlikely to happen by chance
#define VAR_SIG 0x11223344

typedef enum
{
    vartypeInvalid = 0,
    vartypeInt,
    vartypeFloat,
    vartypeDouble,
    vartypeString,
    vartypeMax  // not a valid vartype
} VARTYPE;

typedef struct
{
    VARTYPE type;
#ifdef DEBUG
    uint32_t sig;
#endif // DEBUG
    union data
    {
        int i;
        float f;
        double d;
        char *s;
    };
} VAR;

然后,您可以进行完整性检查:您可以查看type字段的值是否大于vartypeInvalid且小于vartypeMax(并且您永远不需要编辑这些名称在完整性检查代码中;如果添加更多类型,则在列表中的vartypeMax之前添加它们。此外,对于DEBUG版本,您可以检查签名字段sig是否包含某些特定的签名值。 (这意味着初始化VAR实例的初始化代码需要始终设置sig字段。)

如果您执行此类操作,那么如何初始化它?运行时代码将始终有效:

VAR v;

#ifdef DEBUG
v.sig = VAR_SIG;
#endif // DEBUG
v.type = vartypeFloat;
v.data = 3.14f;

如果要在编译时初始化它怎么办?如果你想用整数值初始化它很容易,因为int类型是union中的第一个类型:

VAR v =
{
    vartypeInt,
#ifdef DEBUG
    VAR_SIG,
#endif // DEBUG
    1234
};

如果您使用的是C99兼容版本的C,您实际上可以使用字段名称初始化结构并让它指定任何类型。但是Microsoft C不符合C99,所以如果你想用floatdouble值初始化你的结构,上面就是一场噩梦。 (如果将浮点值转换为整数,C不会只改变类型,它将对值进行舍入;并且我不知道可以获得一个正确表示32位的32位整数值的技巧在C程序中编译时浮动。)

Compile time float packing/punning

如果你正在使用指针,那很容易。只需使联合中的第一个字段名称为指针类型,将指针强制转换为void *并按上面的方式初始化结构(指针将转到1234上面的位置)。

如果您正在阅读由其他人的代码编写的表格,并且您无法添加类型标识符字段,那么我没有一般的答案。我想你可以尝试将指针读出来作为不同的类型,看哪哪个工作?

答案 1 :(得分:0)

只是想添加一些东西,对于那些使用ELF符号表的人来说,我发现DWARF文件中的DIE更容易使用。您可以使用DWARF而不是ELF来获取变量的地址,类型和名称,并且libdwarf具有良好的文档。