首页 > 解决方案 > 如何从其他 C 程序访问共享对象(.so)中的全局变量?

问题描述

如标题所述,我正在尝试从普通 C 程序访问 .so 中的全局变量。

预加载.h:

int var;
void setting(int x);

测试.c:

#include "preload.h"
extern int var;
int main(){
 ... 
 setting(x);
 /* use var */

}

我预计var设置后x仍为var0。

编译:

gcc test.c -o test
gcc -shared -fPIC preload.c -o preload.so -ldl

执行:

LD_PRELOAD=$PWD/preload.so ./test

标签: clinux

解决方案


这段代码在你的test.c...

extern int var;

...声明有一个类型的对象,由整个程序中某处定义int的名称标识。var

这段代码在你的preload.h...

void setting(int x);

... 完全构成了另一个声明所承诺的定义,并且它出现在每个包含标题的翻译单元中,包括test.c. 这使得声明变得test.c多余,但 C 允许这样做。这也意味着程序test提供了自己的对象var

如果您preload.c还包括preload.h,那么它还包含var. 如果你将这两个翻译单元组合成一个程序,那么你就违反了 C 对一个程序包含多个相同标识符的外部定义的明确禁止。未定义的行为结果,您实际观察到的只是轻微的情况。

使您的main()函数能够使用与var您的函数相同的对象的正确方法setting()

  1. 明确声明varin :preload.hextern

    extern int var;
    

    与不包括初始化程序的声明一起,导致声明不能用作定义。这种形式始终是您想在头文件中使用的形式。

  2. varat 文件范围的定义放入preload.c(或任何应被视为拥有该变量的翻译单元中):

    int var;
    
  3. (可选)删除varfrom的冗余声明test.c

但是请注意,这可以实现一个var程序的不同部分之间的共享,包括库中的函数、共享的或静态的。根据您的示例,我认为这就是“来自其他 C 程序”的意思。另一方面,如果您的意思是要在不同的程序之间共享数据,那么将外部对象放入共享库将无法实现。使用此类共享库的每个程序的每个实例仍将获得这些对象的自己的副本。

如果实际上想要跨程序共享数据,那么您将需要为此使用特定于操作系统的机制。Linux 有两种共享内存,System V 和 POSIX。我会推荐后者。但是,如何使用它的详细信息将是另一个答案,而且您已经可以在 StackOverflow 和其他地方多次找到该答案。


推荐阅读