内联定义

pg474,KNKing

“C99中的一般规则是,如果特定文件中函数的所有顶级声明都包含内联而非外部,那么该文件中函数的定义是内联的。”

  • 什么是:“function的顶级声明”??

“如果函数在程序中的任何地方使用(包括包含其内联声明的文件),那么函数的外部声明将需要由其他文件提供。当调用该函数时,编译器可以选择执行一个普通的调用(使用函数的外部定义)或执行内联扩展(使用函数的内联定义)。无法确定编译器将选择哪个选项,因此两个定义保持一致至关重要。“

  • 他在这说什么?

“具有静态存储持续时间的变量是具有外部链接的内联函数的特殊问题”

但我认为你无法通过外部链接调用函数! 编译器会给出一个错误:

第473页

“所以试图从另一个文件中调用平均值将被视为错误”

“因此,C99对具有外部链接的内联函数施加了以下限制(但不对具有内部链接的内联函数施加限制):该函数可能未定义可修改的静态变量。该函数可能不包含对具有内部链接的变量的引用。”

为什么?? 如果函数是内联函数和外部函数,那么即使它确实声明了一个静态int i; 由于函数无法链接到你无法调用它,但是不会在内联函数堆栈框架外创建静态变量 – 所以你应该能够链接到它? 内联函数有堆栈框架吗? 这里发生了什么??

我知道我写了很多,但我试图解释存储和链接的概念和我的文本解释。 希望这可以帮助!

“C99中的一般规则是,如果特定文件中函数的所有顶级声明都包含内联而非外部,那么该文件中函数的定义是内联的。”

什么是:“function的顶级声明”??

函数的声明以与变量声明类似的forms使用。 它是一个声明函数名称,返回类型和参数类型的语句。 函数定义是函数的实际代码。

示例声明:

int foo( int bar ); 

示例定义:

 int foo( int bar ){ return -bar; } 

顶级函数声明只是一个声明,它位于文件范围内(即,在任何块之外)。 这通常是所有函数声明的地方,尽管可以在其他函数内声明和定义函数。

“如果函数在程序中的任何地方使用(包括包含其内联声明的文件),那么函数的外部声明将需要由其他文件提供。当调用该函数时,编译器可以选择执行一个普通的调用(使用函数的外部定义)或执行内联扩展(使用函数的内联定义)。无法确定编译器将选择哪个选项,因此两个定义保持一致至关重要。“

咦??? 他在这说什么?

首先,什么是联动? 变量或函数的链接定义了编译器如何处理该对象的多个实例。 没有联系的标识符总是“个人”。 也就是说,程序中标识符的多个声明总是被视为单独/不同的实体。 函数参数和局部变量没有联系。 对具有外部链接的标识符的所有引用都指向同一实体。 这是C关键字’extern’。 默认情况下,全局标识符具有外部链接。 这意味着,例如,如果你有全局变量“int x;” 在程序的两个源文件中,它们将链接在一起并视为同一个变量。 内部链接意味着一个源文件中的标识符的所有声明都引用单个实体,但是其他源文件中的相同标识符的声明引用不同的实体。 这是使文件“私密”的C方式。 这是文件范围中的C关键字“static”。

现在,回到段落。 函数不能定义多次。 因此,想要使用其他源文件中的函数的源文件需要包含外部声明(这是进行函数调用所需的信息)。 本段解释的是当文件具有内联函数的外部声明时会发生什么。 编译器必须选择是否应该获取内联定义并将其插入调用函数的位置,或者是否应该保留外部链接,使执行跳转到代码文本,就像正常一样; 并且没有办法预测编译器将做出什么选择。

“具有静态存储持续时间的变量是具有外部链接的内联函数的特殊问题”

但我认为你无法通过外部链接调用函数! 编译器会给出一个错误:第473页“因此尝试从另一个文件调用平均值将被视为错误”

如果你不能调用在不同源文件中定义的函数(即外部链接函数),那么C确实是一种非常弱且无聊的语言!

“因此,C99对具有外部链接的内联函数施加了以下限制(但不对具有内部链接的内联函数施加限制):该函数可能未定义可修改的静态变量。该函数可能不包含对具有内部链接的变量的引用。”

为什么?? 如果函数是内联函数和外部函数,那么即使它确实声明了一个静态int i; 由于函数无法链接到你无法调用它,但是不会在内联函数堆栈框架外创建静态变量 – 所以你应该能够链接到它? 内联函数有堆栈框架吗? 这里发生了什么??

静态存储的变量是不属于执行堆栈的变量。 它的空间在程序开始运行之前分配一次,并在整个执行过程中存在。 它们保留其初始值,直到分配不同的值。 默认情况下,全局变量(文件范围)是静态存储的。 这与自动存储的变量形成对比, 自动存储的变量在程序执行进入声明它们的块之前在堆栈上分配,并且在执行离开该块时被丢弃。 默认情况下,局部变量(块范围)是自动的。

回到问题:内联函数中静态存储变量的问题是什么? 函数内的静态存储变量的假设是该函数只有一个定义,因此只有该静态变量的一个定义。 但是,根据定义,内联是函数定义的重复,因此您不需要在函数调用期间跳转代码文本。 如果函数中存在静态变量,那么你将不得不跳转到它的存储位置,从而破坏了内联的目的,即拥有“就在那里”的所有内容的副本。 解决方案:要求变量不可修改,以便编译器可以内联永久值。

关于你的最后一个问题:内联函数确实有一个堆栈框架:它与调用函数的堆栈框架相同,因为正在复制内联函数的代码文本,以避免正常外部函数跳转的标准指令开销。