如何在运行时查找全局变量的地址?

时间:2014-02-28 05:00:01

标签: c

我们知道结构变量和全局变量的地址是在运行时分配的。 我必须将这些地址传递给一个函数。我只有变量的名称存储在二维数组中。怎么可能这样做?

作为一个例子:有一些文件有全局&结构变量。我已从.map文件中收集了数组中的所有变量名,但我想确定变量的地址。

2 个答案:

答案 0 :(得分:5)

您不能将变量的名称作为字符串并将其转换为地址,这称为内省,标准C没有该设施。

可以做的是提供您自己的映射,例如:

int glob_one, glob_two;

typedef struct {
    char *name;
    int  *addr;
} tMap;

tMap map[] = {
    {"glob_one", &glob_one },
    {"glob_two", &glob_two },
};

int *findVar (char *key) {
    for (int i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
        if (strcmp (map[i].name, key) == 0) {
            return map[i].addr;
        }
    }
    return NULL;
}
:
int *glob_to_use = findVar ("glob_two");
if (glob_to_use != NULL)
    *glob_to_use = 42;

如果您使用的是POSIX系统,dlsym可以获取有关全局命名空间的信息:

int glob_one;
:
int *glob_to_use = dlsym (RTLD_DEFAULT, "glob_one");
if (glob_to_use != NULL)
    *glob_to_use = 42;

例如,以下代码:

#include <stdio.h>
#include <dlfcn.h>
int glob_one;
int main (int argc, char *argv[]) {
    int *glob_to_use;
    printf ("Old value is %d\n", glob_one);
    glob_to_use = dlsym (RTLD_DEFAULT, "glob_one");
    if (glob_to_use != NULL)
        *glob_to_use = 42;
    else
        puts (dlerror());
    printf ("New value is %d\n", glob_one);
    return 0;
}

在Linux下编译时使用:

gcc -rdynamic -o testprog testprog.c -ldl

将产生:

Old value is 0
New value is 42

如果您使用的是Windows而不是POSIX系统,则等效的调用是GetProcAddress()。以下是与上述相同的程序:

#include <Windows.h>
#include <iostream>
extern "C" {
    __declspec(dllexport) int glob_one = 13;
}
int main (void) {
    std::cout << "Old value is " << glob_one << '\n';

    HMODULE hMod = GetModuleHandle (NULL);
    int *pGlobal = (int*) GetProcAddress (hMod, "glob_one");
    *pGlobal = 42;

    std::cout << "New value is " << glob_one << '\n';

    return 0;
}

请注意extern "C"dllexport的使用,这两者都是必需的。第一个停止名称修改,因此您可以使用真实名称进行符号查找。第二个导出变量,以便GetProcAddress()可以找到它。

与上面的Linux一样,输出显示您可以通过其文本名称访问全局:

pax> gpatest
Old value is 13
New value is 42

答案 1 :(得分:1)

您可以通过它的名称访问变量的地址,如

int globvar = 5;    // global

{
    int *pglob_myvar = (int *)dlsym(RTLD_NEXT, "globvar");
    printf("global: %d\n",*pglob_myvar);
}