2

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

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

让我们举个例子。你有一个库可以做一些事情,并且在不同的源文件中你可能需要copy_fileand create_directory,所以你可以将它们实现为实用函数。

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

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

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

我采取的做法是这样的:

实用程序.h:

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

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

文件1.c:

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

/* use both functions */

文件2.c

#define USE_COPY_FILE
#include "utils.h

/* use only copy_file */

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

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

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

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

4

2 回答 2

3

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

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

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

于 2012-05-24T10:03:14.753 回答
2

您可以正常链接您的库,使这些函数全局化,并在以后本地化它们。

objcopy可以采用全局符号并使它们成为本地符号,因此它们无法链接。它还可以删除符号(函数保持不变,对它的已解析引用保持已解析,只是名称消失了)。

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

我刚刚发现我在重复这个问题的答案,Oli Charlesworth 在他的评论中提到了这个问题。

于 2012-05-24T09:35:45.893 回答