我有两个问题:
1)为什么在C++中允许指向内联函数的指针?我已经读过内联函数的代码只是被复制到函数调用语句中,内联函数中没有编译时内存分配.那么为什么内联函数存在一个指针,因为内联函数没有固定的内存地址?
2)考虑以下代码:
inline void func() { int n=0; cout<<(&n); }
它是否应该打印不同值的n
每次func()
调用地址?[因为我认为每次复制内联函数代码时,必须重新分配局部变量(而在正常函数的情况下,重新初始化会发生)]
我是初学者,为了加强我的概念,我问了这个问题.如果我在任何地方都错了,请纠正我.
1)为什么在c ++中允许指向内联函数的指针?
因为内联函数就像其他任何函数一样,并且指向它们是您可以使用函数执行的操作之一.内联函数在这方面并不特别.
我已经读过内联函数的代码只是被复制到函数调用语句中,并且内联函数中没有编译时内存分配.
你(也许是你读过的材料)混合了两个相关的,同样命名的概念.
内联函数在使用它的所有翻译单元中定义,而非内联函数仅在一个定义规则的要求下在一个翻译单元中定义.这就是函数的内联声明意味着什么; 它放宽了一个定义规则,但也提供了在使用它的所有翻译单元中定义的额外要求(如果没有放松,则这是不可能的).
内联扩展(或内联)是一种优化,通过将被调用的函数复制到调用者的框架中来避免函数调用.无论函数是否已内联声明,函数调用都可以内联扩展.并且内联声明的函数不一定是内联扩展的.
但是,函数不能在未定义的转换单元中内联扩展(除非链接时优化执行扩展).因此,在内联声明允许的所有TU中定义的要求也允许通过允许在调用它的所有TU中定义函数来实现函数的内联扩展.但优化并不能保证.
2)每次调用func()时是否应该打印不同的n地址值?
内联扩展确实会导致局部变量位于调用者的框架中,是的.但是,如果呼叫来自不同的帧,它们的位置将不同,无论扩展如何.
通常会生成由内联扩展的任何函数生成的常规非扩展版本.如果采用函数的地址,则将指向非扩展函数.如果编译器可以证明对函数的所有调用都是内联的,则编译器可能会选择不提供非扩展版本.这要求该功能具有内部链接,并且获取该功能的地址通常使得这种证明非常困难或不可能.
该inline
关键字原是提示你的程序员认为这个功能是内联的候选人编译器-兑现这个编译器不是必需的.
在现代的使用中,它与内联几乎没有任何关系 - 现代编译器可以自由地内联(或不支持)功能"在你身后",这些构成了优化技术的一部分.
代码转换(包括内联)是在C++中的"as-if"规则下完成的,这基本上意味着编译器可以根据需要转换代码,只要执行是"as-if"原始代码被执行如写的.这条规则推动了C++的优化.
也就是说,一旦获取了函数的地址,就需要存在(即地址必须有效).这可能意味着它不再内联,但仍然可以(优化器将应用适当的分析).
那么为什么指针内联函数没有固定的内存地址,为什么内联函数会存在指针呢?
不,这只是一个提示,主要与联系有关,而不是实际的内联.这可以说是主要的当前用法,它定义了头文件中的功能.
如果不打印
n
每次func()
调用不同的地址值?
它可能n
是一个局部变量,基于函数执行时的堆栈位置.也就是说,函数inline
,它涉及链接,链接器将合并功能翻译单元.
如评论中所述 ;
...如果示例更改为
static int n
,则对函数的每次调用都必须打印一个常量值(当然在单个程序运行中)......无论代码是否内联,都是如此.
这又是连接要求对局部变量的影响n
.
你读旧材料.使用inline
nowdays的主要原因是允许头文件中的函数体.使用inline
带有函数的关键字向链接器发出信号,表示可以组合跨翻译单元的所有函数实例; 在多个单元中包含的标头中具有非内联函数会导致由于单一定义规则违规而导致的未定义行为.
C++ 17还添加了内联变量,这些变量具有与标头中定义的变量相同的属性,并且所有定义都由链接器组合而不是导致ODR违规.
您正在谈论的"将代码复制到调用函数"的内容称为内联,并且与inline
关键字无关.编译器将根据优化设置决定是否对非内联函数以及内联函数执行此操作.
内联函数并不总是内联.它只是表明程序员希望内联这个函数.允许编译器内联任何函数,无论是否使用了内联关键字.
如果使用函数的地址,则该函数很可能不会在最终的可执行文件中内联,至少在GCC中:
当函数既是内联函数又是静态函数时,如果对函数的所有调用都集成到调用者中,并且从不使用函数的地址,则永远不会引用函数自己的汇编代码.
GCC文档