我知道内联函数要么被调用,要么被调用,或者表现为普通函数。
但是我怎么知道内联函数是否实际被替换在它被调用的地方,因为将内联函数作为内联处理的决定是在编译时?
答案 0 :(得分:58)
在运行时以编程方式,你不能 事情的真相是: 你不需要知道
编译器可以选择inline
未标记为inline
的函数或忽略明确标记为inline
的函数,这完全是希望(读取智慧)编译器&你应该相信编译器能够明智地完成它的工作。大多数主流编译器都能很好地完成它们的工作。
如果您的问题纯粹来自学术观点,那么有几种选择:
您可以检查汇编代码以检查函数代码是否在调用时内联。
如何生成汇编代码?
对于gcc:
编译时使用-S
开关
例如:
g++ -S FileName.cpp
生成的汇编代码创建为文件FileName.s
。
对于MSVC:
从命令行使用 /FA Switch 。
在生成的汇编代码中查找是否存在特定函数的call
汇编指令。
如果某些编译器未能遵守内联函数请求,则会发出警告
例如,在gcc中,如果编译器没有内联声明为内联的函数,-Winline
命令选项将发出警告。
查看 GCC documentation 了解更多详情:
-Winline
如果无法内联声明为内联的函数,则发出警告。即使使用此选项,编译器也不会警告系统头中声明的内联函数失败。
编译器使用各种启发式方法来确定是否内联函数。例如,编译器会考虑内联函数的大小以及当前函数中已经完成的内联量。因此,源程序中看似无关紧要的更改可能会导致
-Winline
产生的警告出现或消失。
答案 1 :(得分:10)
检查生成的代码。如果函数被展开,你将看到它的主体,而不是call
或类似的指令。
答案 2 :(得分:7)
您可以使用工具在Linux上列出目标文件中的符号,例如nm
。如果函数是内联的,它将不会列在nm
输出中 - 它成为其他函数的一部分。此外,您将无法在调试器中按名称将断点放在此函数上。
答案 3 :(得分:4)
使用gdb,如果你不能调用一个函数,它的一个可能含义是函数是内联的。翻转推理,如果你可以在gdb中调用一个函数,意味着该函数没有内联标记。
答案 4 :(得分:4)
如果您需要确保内联函数并且可以使用MS VC ++中的专有扩展,check out the __forceinline
declarator。编译器将内联函数,或者,如果它属于记录的特殊情况列表,您将收到警告 - 因此您将知道内联状态。
不以任何方式支持它。
答案 5 :(得分:3)
内联或不是函数的决定由编译器决定。由于它是由编译器生成的,所以是的,它只能在编译时生成。
因此,如果您可以使用-S选项查看汇编代码(使用gcc -S生成汇编代码),您可以查看您的函数是否已内联。
答案 6 :(得分:0)
答案 7 :(得分:0)
以上回答非常有用,我只是在编写内联函数时添加了一些我们记在心里的观点。
请记住,内联只是对编译器的请求,而不是命令。编译器可以忽略内联请求。 编译器可能无法在:
等情况下执行内联1)如果函数包含循环。 (for,while,do-while)
2)如果函数包含静态变量。
3)如果函数是递归的。
4)如果函数返回类型不是void,并且函数体中不存在return语句。
5)如果函数包含switch或goto语句。
答案 8 :(得分:0)
有一种方法可以确定函数是否以编程方式内联,而无需查看汇编代码。答案取自here。
说您要检查是否内联特定呼叫。你会像这样去。编译器内联函数,但是对于那些导出的函数(几乎所有函数都是导出的),它需要维护一个非内联可寻址函数代码,该代码可以从外部调用。
要检查函数my_function
是否内联,需要将my_function
函数指针(未内联)与PC的当前值进行比较。这是我在环境中(GCC 7,x86_64)所做的操作:
void * __attribute__((noinline)) get_pc () { return _builtin_return_address(0); }
void my_function() {
void* pc = get_pc();
asm volatile("": : :"memory");
printf("Function pointer = %p, current pc = %p\n", &my_function, pc);
}
void main() {
my_function();
}
如果未内联函数,则PC的当前值与函数指针的值之间的差应较小,否则应较大。在我的系统上,当未内联my_function
时,将得到以下输出:
Function pointer = 0x55fc17902500, pc = 0x55fc1790257b
如果函数是内联的,我得到:
Function pointer = 0x55ddcffc6560, pc = 0x55ddcffc4c6a
对于非内联版本差异为0x7b
,对于内联版本差异为0x181f
。
答案 9 :(得分:-1)
如果函数返回一个地址,则编译器不会使其内联。