如何在没有外部链接的情况下在翻译单元之间共享一组内部功能?

时间:2012-05-24 09:29:58

标签: c static external static-libraries linkage

假设您正在编写一个库,并且您拥有一堆只为自己编写的实用函数。当然,您不希望这些函数具有外部链接,以便它们不会被您的图书馆用户混淆(主要是因为您不会告诉外界他们的存在)

另一方面,这些功能可以在不同的翻译单元中使用,因此您希望它们在内部共享。

我们举个例子。您有一个库可以执行某些操作,并且可能需要copy_filecreate_directory的不同源文件,因此您可以将它们实现为实用程序函数。

为了确保您的库的用户不会因为具有相同名称的功能而意外地收到链接错误,我可以考虑以下解决方案:

  • 可怕的方法:将函数复制粘贴到使用它们的每个文件中,并在其声明中添加static
  • 不是一个好方法:将它们写成宏。我喜欢宏,但这不是就在这里。
  • 给他们这样一个奇怪的名字,用户生成相同名称的机会足够小。这可能有效,但它使得使用它们的代码非常难看。
  • 我目前的工作:将它们作为static函数写入内部utils.h文件,并将该文件包含在源文件中。

现在最后一个选项几乎没有问题,除了它有一个问题:如果你不使用其中一个函数,至少你得到一个警告(说明函数声明为静态但从未使用过)。叫我疯了,但我保持我的代码免费警告。

我采取的行动是这样的:

utils.h:

...
#ifdef USE_COPY_FILE
static int copy_file(/* args */)
{...}
#endif

#ifdef USE_CREATE_DIR
static int create_dir(/* args */)
{...}
#endif
...

file1.c中:

#define USE_COPY_FILE
#define USE_CREATE_DIR
#include "utils.h"

/* use both functions */

file2.c中

#define USE_COPY_FILE
#include "utils.h

/* use only copy_file */

然而,这种方法的问题在于,随着更多实用程序的引入,它开始变得丑陋。想象一下,如果你有10个这样的函数,你需要在include之前有7~8行定义,如果你需要7~8个这些函数的话!

当然,另一种方法是使用排除函数的DONT_USE_*类型的宏,但是对于使用这些实用函数的文件,你需要很多定义。

无论哪种方式,它看起来都不优雅。

我的问题是,您如何拥有自己库内部的功能,由多个翻译单元使用,并避免外部链接?

2 个答案:

答案 0 :(得分:3)

标记功能static inline而不是static会使警告消失。它对你当前解决方案的代码膨胀没有任何作用 - 你将至少一个函数副本放入每个使用它的TU中,这仍然是这种情况。 Oli在评论中说,链接器可能足够聪明,可以合并它们。我不是说它不是,但不要依赖它: - )

通过鼓励编译器实际内联对函数的调用,以便每个TU获得多个副本, 可能甚至会使恶化更糟糕。但这不太可能,GCC大多忽略了inline关键字的这一方面。它根据自己的规则内联或不调用。

这基本上是你能做到的最好的便携。标准C中无法定义某些TU(您的POV)的外部符号,而不是其他人(您的用户)的POV。标准C并不真正关心库是什么,或者TU可能在几个步骤中链接的事实,或静态和动态链接之间的区别。因此,如果您希望功能在您的TU之间实际共享,而没有任何可能干扰库用户的外部符号,那么您需要执行特定于GCC和/或静态库或dll格式的操作以删除符号一次该库是在用户链接之前构建的。

答案 1 :(得分:2)

您可以正常链接您的库,将这些函数设置为全局,并在以后对其进行本地化。

objcopy可以使用全局符号并将其设置为本地符号,因此无法将它们链接起来。它也可以删除符号(函数保持不变,对它的解析引用仍然被解析,只是名称消失了。)

objcopy -L symbol本地化symbol。您可以多次重复-Lobjcopy -G symbol保持symbol全局,但将其他所有内容本地化。您也可以重复它,它将保持您指定的全局。

我刚刚发现我正在重复this question的答案,Oli Charlesworth在评论中提到了这个答案。