如果未调用引用的库函数,它是否会被链接?

时间:2013-05-13 13:34:47

标签: c standards linkage

假设我们有一个库的以下接口:

// my_interface.h
typedef float (*myfunc)(float);
myfunc get_the_func();

并假设实施如下:

// my_impl.c
#include <math.h>
myfunc get_the_func() {
    return sinf;
}

现在假设客户端代码执行以下操作:

#include "my_interface.h"
...
myfunc func = get_the_func();
printf("%f\n", func(0.0f));

标准是否保证get_the_function()将返回标准数学库sinf()的地址?如果是这样,标准中的这个含义是什么? 请注意,sinf()未在任何地方显式调用。

3 个答案:

答案 0 :(得分:6)

该标准不需要调用外部函数:被引用就足以保留在翻译结果中。根据标准的5.1.1.2.1节,在翻译的八个阶段(和最后一个阶段)

  

解决所有外部对象和函数引用。链接库组件以满足对当前转换中未定义的函数和对象的外部引用。

由于返回指向函数的指针被认为是对它的引用,因此标准保证sinf将链接到您提供给链接器的任何实现,这些实现可能是也可能不是来自链接器的实现。标准数学库。

答案 1 :(得分:3)

C标准不保证get_the_function()将返回数学库中sinf函数的地址。 C标准保证无论返回什么指针都可以调用,就像你调用sinf函数一样,它将与该函数的任何其他指针进行比较。

在某些体系结构上,您可能会获得指向编译器特定处理函数的描述符的指针,并且我还看到了指向动态链接蹦床的函数指针值,而不是函数本身。

我回忆起大约10年前对gcc邮件列表的讨论,如果一个函数指针转换为(void *)实际上需要比较等于另一个函数指针强制转换为(void *),这与IA64实现函数的方式有关指针(它们可以指向不同库中的不同描述符结构,这意味着要正确实现比较,编译器必须比较描述符的内容而不是指针本身)。但我不记得标准律师的决定和/或是否在链接器中解决了这个问题。

答案 2 :(得分:0)

好的,所以NOWHERE在标准中说它只是因为你#include <math.h>你也会链接到标准的数学库......事实上,这不会发生。

您必须链接到libm才能使用标准数学库,如:

cc -o foo foo.c -lm 
                ^^^^

标记的选项实际上是链接器步骤,没有链接,无论您是将库中的函数作为返回值还是使用它实际调用该函数。

通过显式指定存档/对象/库或在运行时通过动态链接进行系统/环境延迟链接的情况下,可以解析外部符号。

在支持动态链接,弱链接,延迟链接等的环境中,无法保证引用将被解析。对于解决方案,必须遍历执行路径。

让我们说是的。尽管如此,您的客户端还需要提供一个链接路径来解析 sinf ,无论是在链接时还是在运行时为支持它的环境。

要点:

客户端用户可以使用任何方式将符号解析为他们认为合适的地址;因此,事实上,没有办法保证您的客户端将链接到标准库,并且它将解析为系统库sinf。你唯一知道的是,如果该路径被执行;它将导致一个可以使用sinf链接查找的地址,或者它会毫不客气地崩溃,以便在链接时不必解析符号的环境。

更新/澄清:

澄清一下,如果sinf用作变量;然后它需要解决,但仍然无法保证当客户端代码通过其链接步骤解析符号时,他们将针对数学库解析它。如果我们谈论的是保证。

现在实际上,如果客户端链接到标准数学库并且没有提取它们可以执行的任何覆盖(我在上面指出)那么是符号将被解析为需要与标准的链接库(静态或动态)

我原来的答案有点“傲慢”,我为此道歉,因为我们谈论的是标准和保证因此是愚蠢的性质。没有什么可以阻止客户简单地做这样的事情:

foo.c的:

#include "my_interface.h"
...
myfunc func = get_the_func();
printf("%f\n", func(0.0f));

首先通过编译:

cc -o foo foo.c

收到错误消息,指出sinf未解析,因此客户端编辑了她的源文件:

foo.c的:

#include "my_interface.h"
...
void * sinef = NULL;
myfunc func = get_the_func();
printf("%f\n", func(0.0f));

现在你有一个完全解决但很好的崩溃程序;