1

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

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

0x8c334dd

存储在 char 变量中。这个地址是另一个有数据的变量的地址。我想做的是去那个地址并获取存储在上面的数据。

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

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

我正在使用 ELF 符号表

4

2 回答 2

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,所以如果你想用floatordouble值初始化你的结构,上面是一场噩梦。(如果将浮点值转换为整数,C 不仅会更改类型,还会对值进行四舍五入;而且我知道没有任何技巧可以可移植地获取正确表示 32 位的 32 位整数值在 C 程序的编译时浮动。)

编译时浮动包装/双关语

但是,如果您使用指针,那很容易。只需将联合中的第一个字段名称设置为指针类型,将指针转换void *为上面的结构并初始化结构(指针将转到1234上面的位置)。

如果您正在阅读由其他人的代码编写的表格,并且您没有办法添加类型标识符字段,那么我没有给您一个通用的答案。我想您可以尝试将指针读取为不同的类型,然后看看哪些有效?

于 2012-09-17T21:28:38.417 回答
0

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

于 2012-09-18T18:40:02.620 回答