C:指向内联函数的指针

16

我有一个在H文件中定义的static inline函数,在C文件的某个位置,我正在将指针分配给该函数,类似于以下内容:

foo.h:

static inline void frobnicate(void) {
    // frobs something.
}

foo.c

#include "foo.h"

void execute(void (*func)(void) ) {
    func();
}

void blahBlahBlah(void) {
    execute(frobnicate);
}

bar.c

#include "foo.h"
// ...
frobnicate();

所以我认为这里会发生的是:编译器将内联来自bar.c的对frobnicate的调用,但在foo.c中,它实际上必须创建一个函数来实现frobnicate,以便可以有一个有效的指向它的指针。

有人可以确认我的理解是否准确,并纠正我吗?


3
你可以通过阅读生成的代码来确认它。我认为没有规定它必须按照某种特定方式工作。如果编译器认为“有人需要这个的地址,所以不要将其内联”,那我也不会感到惊讶。 - unwind
7
请记住,inline 只是对编译器的一个「建议」。 - Seth Carnegie
它同样可以推断,它可以直接将 frobnicate 内联到 blahBlahBlah 中,跳过中间人。没有指向 frobnicate 的指针被存储在允许从另一个翻译单元使用它的方式中,因此 frobnicate 不需要存在于汇编输出中。 - Petr Skocik
2个回答

11

inline是C标准的一个误称,它的主要意义是可以在头文件中放置函数定义,而不需要在链接时处理“多重定义”问题。

C99和C11的官方实现方式是,在头文件中使用inline定义,但不使用static。由于您还需要发出符号,因此需要告诉编译器在哪个编译单元中进行实例化。可以通过在那个.c文件中使用声明来进行这样的实例化,其中省略了inline关键字。

最自然的方法是使用实际需要该符号的.c文件。


如果内联定义在头文件中没有使用 static,那么在链接时我会不会有多个相同名称(即内联函数)的定义? - brianmearns
你将会遇到链接问题。要么将其设为static inline,并冒多重定义的风险,要么放弃内联。你也可以创建一个包装器,在C文件中,并且不是内联的,然后将指针传递给它(没有性能损失,因为真正的函数将被内联到包装器中)。 - ugoren
1
@bmearns,使用符合C99标准的编译器,您将不会遇到任何链接问题。这正是“inline”关键字的意义所在。http://gustedt.wordpress.com/2010/11/29/myth-and-reality-about-inline-in-c99/ - Jens Gustedt
@Jens:谢谢,那个链接让我更加清楚了。虽然我不太确定编译器是如何处理它的,但我认为我知道如何应用它了。 - brianmearns

10

是的,你说得对。当你将指针指向函数时,编译器必须创建一个“独立”的版本,以便可以像普通函数一样调用代码。

将函数内联的好处在于调用代码无需被创建,并且任何其他优化都可以应用于集成调用者函数和内联函数。但是当您需要定期调用该函数时(例如当您获取地址以便稍后调用它),这些优化将不再可行。


2
这可能对许多编译器来说是正确的,但我无法想象为什么编译器需要这样做。即使在函数指针的情况下,OP的示例也可以很容易地进行内联处理。 - user180326
“inline”是一种建议。如果编译器无法进行内联,它就不会这样做,即使可以进行内联,它也可能决定不这样做(并且即使没有“inline”关键字,它也可能进行内联)。函数指针通常会阻止内联,但在这种情况下,编译器可能会发现它们不会阻止内联(或者它可能不会费心去尝试)。 - ugoren
是的,在这种情况下,可以将函数内联。我假设这是问题的简化版本。但你是对的。 - Governa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接