我正在写一个C(共享)库。它起初是一个单独的翻译单元,我可以在其中定义几个static
个全局变量,以便从外部模块中隐藏。
现在库已经增长,我想将模块分成几个较小的源文件。问题是现在我有两个选项用于提到的全局变量:
在每个源文件中都有私有副本,并通过函数调用以某种方式同步它们的值 - 这将非常快速地变得非常丑陋。
删除static
定义,因此使用extern
在所有翻译单元之间共享变量 - 但现在,与库链接的应用程序代码可以访问这些全局变量,如果需要的声明就在那里。
那么,是否有一种巧妙的方法可以在多个特定的翻译单元之间共享私有全局变量?
答案 0 :(得分:7)
您需要GCC的visibility attribute扩展名。
实际上,类似于:
#define MODULE_VISIBILITY __attribute__ ((visibility ("hidden")))
#define PUBLIC_VISIBILITY __attribute__ ((visibility ("default")))
(你可能想要#ifdef
上述宏,使用一些配置技巧àautoconf
和其他 autotools ;在其他系统上你只需要空像#define PUBLIC_VISIBILITY /*empty*/
等定义......)
然后,声明一个变量:
int module_var MODULE_VISIBILITY;
或函数
void module_function (int) MODULE_VISIBILITY;
然后,您可以在共享库中使用module_var
或致电module_function
,但不能在外部使用。
另请参阅GCC的-fvisibility代码生成选项。
顺便说一句,您也可以使用-Dsomeglobal=alongname3419a6
编译整个图书馆,并像往常一样使用someglobal
;要真正找到它,您的用户需要将相同的预处理器定义传递给编译器,并且您可以使名称alongname3419a6
随机且不可能,以使碰撞不可能。
PS。这种可见性特定于GCC (可能到ELF共享库,例如Linux上的那些)。如果没有GCC或共享库之外它将无法工作....因此非常特定于Linux(即使其他一些系统,也许是带有GCC的Solaris)。可能一些其他编译器(来自LLVM的clang
)也可能支持在Linux 上用于共享库(不是静态的)。实际上,真正的隐藏(对于单个共享库的几个编译单元)主要由链接器完成(因为ELF共享库允许)。
答案 1 :(得分:4)
最简单的(“老派”)解决方案是不要在预期的公共标题中声明变量。
将库标题拆分为“header.h”和“header-internal.h”,并在后者中声明内部内容。
当然,您还应该注意保护库全局变量的名称,以免它与用户代码冲突;大概你已经有了一个用于此功能的前缀。
您还可以将变量包装在struct
中,以使其更清晰,因为只有一个实际符号是全局可见的。
答案 2 :(得分:2)
如果您真的想尽可能隐藏信息,可以使用伪装结构来混淆事物。例如在头文件中,
struct data_s {
void *v;
};
在你的来源的某个地方:
struct data_s data;
struct gbs {
// declare all your globals here
} gbss;
然后:
data.v = &gbss;
然后,您可以通过((struct gbs *)data.v)->
答案 3 :(得分:0)
我知道这不是你想要的,但是你可以将全局变量保持为静态并将它们分成多个源文件。
将写入相应静态变量的函数复制到同样声明为static的源文件中。
声明读取静态变量的函数,以便同一模块的外部源文件可以读取它的值。
在某种程度上减少全球化。如果可能,将大文件分解为较小文件的最佳逻辑是根据数据做出决定。
如果无法以这种方式执行此操作,则可以将所有全局变量作为静态压缩到一个源文件中,并通过函数从模块的其他源文件访问它们,使其正式化,以便有人操纵您的全局变量至少你知道如何。 但是,使用@ unwind&time方法可能更好。