在《C++程序设计语言》一书的第7.1.1节中,作者提到:“内联函数仍然具有独特的地址,内联函数的静态变量也是如此。”我感到困惑。如果我有一个内联函数,它就不能具有地址。这在C语言中也会发生吗?
inline
属性只是一个给编译器的提示,让它尝试内联你的函数。仍然可以获取函数的地址,在这种情况下,编译器还需要生成非内联版本。
例如:
#include <stdio.h>
inline void f() {
printf("hello\n");
}
int main() {
f();
void (*g)() = f;
g();
}
上面的代码会打印两次“hello”。
我的gcc编译器(使用-O选项)生成的代码大致如下:_main:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
call ___i686.get_pc_thunk.bx
"L00000000002$pb":
leal LC0-"L00000000002$pb"(%ebx), %eax
movl %eax, (%esp)
call L_puts$stub ; inlined call to f()
call L__Z1fv$stub ; function pointer call to f() (g is optimised away)
movl $0, %eax
addl $20, %esp
popl %ebx
popl %ebp
ret
正如你所看到的,首先调用了puts()
,然后调用了L__Z1fv()
(这是f()
的名称编码)。
如果您需要一个地址,内联函数将具有地址。标准只规定:
带外部链接的内联函数在所有翻译单元中应该具有相同的地址。
没有矛盾。 在调用内联函数的部分,其代码可以进行内联处理。 在使用函数指针的部分,可以创建一个非内联版本以获取地址。
内联函数的扩展没有地址,但如果该函数有静态变量,则变量会具有地址。静态变量基本上只是一个全局变量,其名称仅在本地可见(即在定义它的作用域内)。内联函数中的其他变量可能会在堆栈上分配(就像它们不是内联扩展时一样)或者它们只能存在于机器寄存器中。重要的部分是它们仍然是单独的变量,并且必须像函数没有被内联扩展一样运作(与宏不同,需要极度小心,以防止多次评估引起问题)。
我认为你混淆了内联函数对象代码的位置和内联的含义。通常我们将内联函数视为在源代码级别的调用函数中放置。书中所说的是,变量名称(包括内联函数中使用静态变量)与实际上是典型的独立函数一样处理。
此外,带有inline关键字的函数的处理并不保证它们会被内联,对于无法内联的情况(例如需要地址时),将生成非内联版本。