如何隐藏跨多个文件可见的全局variables?

我正在写一个C(共享)库。 它开始作为一个单一的翻译单位,我可以定义一个static全局variables,从外部模块隐藏。

现在,图书馆已经成长,我想把这个模块分解成几个较小的源文件。 问题是,现在我有两个select提到的全局:

  1. 有每个源文件的私人副本,并以某种方式通过函数调用同步它们的值 – 这将变得非常快非常难看。

  2. 除去static定义,所以使用extern在所有的翻译单元之间共享variables – 但现在,如果在那里进行所需的声明,那么与库链接的应用程序代码就可以访问这些全局variables。

那么,是否有一个简洁的方法可以使私人全局variables跨多个特定的翻译单元共享?

您希望GCC的可见性属性扩展。

实际上,如下所示:

  #define MODULE_VISIBILITY __attribute__ ((visibility ("hidden"))) #define PUBLIC_VISIBILITY __attribute__ ((visibility ("default"))) 

(你可能想#ifdef上面的宏,使用一些配置技巧àla autoconf和其他自动工具 ;在其他系统上,你只需要像#define PUBLIC_VISIBILITY /*empty*/ etc …这样的空定义)

然后,声明一个变量:

 int module_var MODULE_VISIBILITY; 

或者一个功能

 void module_function (int) MODULE_VISIBILITY; 

然后你可以在你的共享库里使用module_var或者调用module_function ,但是不能在外面。

另请参阅GCC的-fvisibility代码生成选项。

顺便说一句,你也可以用-Dsomeglobal=alongname3419a6编译你的整个库,并像往常一样使用someglobal ; 要真正找到它,你的用户需要将相同的预处理器定义传递给编译器,并且你可以使用随机的名字和不可能的名字来使得碰撞变得不可能。


PS。 这种可见性是特定于GCC (也可能是ELF共享库,如Linux上的)。 如果没有GCC或者共享库之外的话,它将无法工作….所以Linux特有的特性(即使其他一些系统,也许还有带GCC的Solaris)。 可能其他一些编译器(来自LLVM的 clang )可能也支持在Linux共享库 (而不是静态的)。 实际上,真正的隐藏(对单个共享库的几个编译单元)主要由链接器完成(因为ELF共享库允许)。

最简单的(“老派”)解决方案是简单地不在预期的公共头中声明变量。

将你的库头分割成“header.h”和“header-internal.h”,并在后者中声明内部的东西。

当然,你也应该注意保护你的库全局变量的名字,以免碰到用户代码; 大概你已经有了一个用于这个目的的函数的前缀。

你也可以将变量包装在一个struct ,使其变得更清洁,因为只有一个实际的符号是全局可见的。

如果您真的想尽可能最好地隐藏信息,您可以用变相的结构来混淆事物。 例如在头文件中,

 struct data_s { void *v; }; 

在你的来源的某个地方:

 struct data_s data; struct gbs { // declare all your globals here } gbss; 

接着:

data.v = &gbss;

然后可以通过以下方式访问所有全局变量: ((struct gbs *)data.v)->

我知道这不会是你的字面意思,但你可以将全局变量保持静态,并将它们分成多个源文件。

将写入相应静态变量的函数复制到同样声明为静态的源文件中。

声明读取静态变量的函数,以便相同模块的外部源文件可以读取它的值。

使其不那么全球化。 如果可能的话,把大文件分解成小文件的最佳逻辑就是根据数据做出决定。

如果这样做是不可能的,那么你可以把所有的全局变量都打包成一个静态的源文件,并且通过函数从模块的其他源文件中获取它们,这样做是正式的,所以如果有人正在操作你的全局变量至少你知道如何。 但是,最好使用@ unwind的方法。