【问题标题】:Differentiate extern inline and inline in C [duplicate]在C中区分extern inline和inline [重复]
【发布时间】:2018-01-10 16:42:11
【问题描述】:

我正在尝试了解外部内联和内联函数。

What's the difference between static inline, extern inline and a normal inline function?

引用上述链接中的行: “只有内联的函数定义定义了具有外部链接的内联函数。但是,这种定义称为内联定义,它不能作为该函数的外部定义。这意味着即使该函数具有外部链接,它也会被其他翻译单元视为未定义,除非您在某处为其提供单独的外部定义。

具有extern inline 的函数定义定义了具有外部链接的内联函数,同时该定义用作该函数的外部定义。可以从其他翻译单元调用此类函数。”

但我无法正确理解这一点。

我有一个示例代码来解释我的理解:

  1. 内联函数:

在 temp1.c 中

#include <stdint.h>
extern int32_t fun1(void);

int32_t main(void)
{
  int32_t result = fun1(); 
  return result;  
}

在 temp2.​​c 中

#include <stdint.h>

int32_t fun1(void);
inline int32_t fun1(void)
{
   return 0;
}

由于 fun1 是 temp2.​​c 中的内联定义,因此它将被视为从 temp1.c 未定义。因此 temp1.c 中的外部声明使 temp1.c 可以从 temp2.​​c 访问 fun1。我很困惑,因为引号中说的是“单独的外部定义”而不是外部声明。

  1. 外部内联函数

temp1.c

#include <stdint.h>

int32_t fun1(void);
int32_t main(void)
{
  int32_t result = fun1(); 
  return result;  
}

temp2.​​c

#include <stdint.h>

extern inline int32_t fun1(void)
{
  return 0;
}

由于 fun1 是外部内联函数,所以可以从 temp1.c 中调用。 我观察到的唯一区别是,不需要显式声明定义它的外部内联函数。

这是唯一的区别吗?否则内联和外联内联函数的其他主要区别和范围是什么?

以上观点如有错误请指正

【问题讨论】:

标签: c inline


【解决方案1】:

关于第一个“内联函数”示例,您说(突出显示添加到函数名称),

由于fun1 是 temp2.​​c 中的内联定义,因此将被视为 从 temp1.c 未定义。所以 temp1.c 中的外部声明 temp1.c 从 temp2.​​c 访问fun1

你的解释不正确,或者至少是用词错误在此示例中,您的 temp2.​​c 未提供函数 fun1() 的外部定义。 temp1.c 中的声明说有一个外部定义somewhere,但 temp2.​​c 不是那个地方。需要有一些其他翻译单元提供的外部定义temp2.​​c 中的函数fun1 是一个内联函数,因为它是用inline 关键字声明的(这就是“内联函数”的全部含义),但是该文件中的fun1 不是内联 定义,因为 temp2.​​c 包含另一个不包含inline 关键字的标识符声明。由于fun1 是用(隐式)外部链接声明的,所以这是fun1 的一个外部定义。任何人都可以调用它。要获得函数的内联定义,在 TU 中对其标识符的每个声明都必须包含 inline 关键字,并且必须省略 extern 关键字。

如果要从该 TU 调用该函数,标准 C 确实需要在 temp1.c 中声明该函数,但您放入该文件中的任何内容都不能使其中的代码访问 fun1 的内联定义一个不同的TU。只有外部定义可以跨 TU 访问——这就是外部定义的含义。

注意:此答案这部分的原始(现已删除)文本假定 temp2.​​c 确实提供了函数 fun1 的内联定义,因为我忽略了声明中的缺陷(?)。

我很困惑,因为它在引号中 是说“单独的外部定义”而不是外部 声明。

函数定义包含该函数的声明,但并非每个函数声明都是定义的一部分。我们必须小心我们这里的措辞。 C 中的“外部函数声明”没有任何意义,因为没有声明的范围比它的翻译单元更宽。

但是人们可以并且经常会使用外部链接对函数进行(本地)声明。这是默认值,适用于所有不包含关键字static 的函数声明。该默认值可以通过使用 extern 关键字来明确表示,而这恰好对内联函数的声明具有额外的意义。

另一方面,外部函数定义是可以从另一个翻译单元按名称访问的函数。明确的内联定义不是外部定义。因此,您的第一个示例声明有一个带有外部链接的函数 fun1,但如果该标识符的所有声明都带有 inline 关键字而不是 extern,那么它不会提供该函数的相应外部定义。如果该函数 is 被调用,即使是从提供内联定义的源文件中调用,那么缺少外部定义 is 将是一个错误。


关于第二个“外部内联函数”示例,您说(突出显示添加到函数名称),

由于fun1是extern内联函数,所以可以从temp1.c调用。

让我们在这里分离出属性。

  • fun1 (仍然)被声明为具有外部链接的函数。
  • 声明中作为其定义一部分的 inline 说明符的存在使其成为内联函数。
  • 显式 extern 说明符出现在与定义相同的翻译单元中的该函数声明中,使该 TU 中的定义成为外部定义。

temp2.​​c 中的定义是一个外部定义,这使得它可以从 temp1.c 调用。

我观察到的唯一区别是,不需要明确 定义它的外部内联函数的声明。

在第一个例子中也不需要fun1() 的前向声明。如果 temp2.​​c 在函数定义之前包含对 fun1 的调用,则在 both 情况下都需要前向声明。这里没有区别。


更新:

你或多或少是对的。您的两种选择是声明具有外部链接的内联函数并为其提供外部定义的不同方法。相反,你应该比较的东西,以及这个答案的原始文本被错误地处理的东西,将是:

#include <stdint.h>

inline int32_t fun1(void);

inline int32_t fun1(void)
{
   return 0;
}

或者,等效地,这个:

#include <stdint.h>

inline int32_t fun1(void)
{
   return 0;
}

在这些情况下,fun1 提供的定义是内联定义,只能从 temp2.​​c 的翻译单元访问。当然,除非 TU 中有实际调用该函数的代码,否则这没什么用。


这是唯一的区别吗?其他主要区别是什么 以及 inline 和 extern 内联函数的范围?

您试图将“inline”和“extern inline”设置为函数类,这是对自己的伤害。有内联函数和非内联函数。有内部链接的函数标识符和外部链接的函数。有内联函数定义、内部函数和外部函数,在一个 TU 中出现函数声明并不一定需要在同一个 TU 中定义。这些属性的这些组合(并且只有这些)是可能的:

  • 函数标识符用外部链接声明,函数不是内联函数,并且函数的外部定义出现在TU中
  • 函数标识符用外部链接声明,函数不是内联函数,并且函数的没有定义出现在TU中宣言。 如果函数标识符在 TU 中被引用,则外部定义出现在不同的 TU 中。
  • 函数标识符用外部链接声明,函数内联函数,函数的内联定义出现在TU中。 如果函数标识符在 TU 中被引用,则外部定义出现在不同的 TU 中。
  • 函数标识符是用外部链接声明的,显式,函数内联函数和外部定义 功能出现在TU中
  • 函数标识符用内部链接声明,函数不是内联函数,函数的内部定义出现在TU
  • 函数标识符用内部链接声明,函数不是内联函数,函数的没有定义出现在TU . 函数标识符从未在该 TU 中引用。
  • 函数标识符用internal links声明,函数内联函数,函数的内联定义出现在TU中

在给定 TU 中使用外部链接声明的函数标识符指的是外部函数定义,它可能出现在不同的 TU 中。

在给定 TU 中使用内部链接声明的函数标识符指的是同一 TU 中的内部或内联函数定义。

内联函数声明可以具有外部或内部链接,在任何一种情况下,该函数的内联定义都必须出现在同一个 TU 中。如果函数标识符具有外部链接(在该 TU 中)和内联函数定义,则由实现自行决定是否在该 TU 内使用内联定义或(必需的)外部定义以及在何处使用。


更新:

经过反思,您将函数本身描述为“内联函数”和“外部内联函数”似乎反映了函数的内联字符全局与函数标识符相关联的想法(例如fun1),至少对于具有外部链接的标识符。事实并非如此,我希望我的冗长演讲已经传达了这一点。

函数标识符的内联字符是每个 TU 的属性,而函数定义的内联字符是一个单独的、每个定义的属性。如果在任何 TU 中将给定函数声明为内联函数,则必须在该 TU 中提供该函数的定义。来自不同 TU 的函数的外部定义不满足该要求,即使该函数在定义出现的 TU 中声明为内联函数。

【讨论】:

  • 正确理解有些困难。案例 1:“temp1.c 中的声明说某处有外部定义,但 temp2.​​c 不是那个地方。需要有其他翻译单元提供的外部定义。” ..但是当我编译它时, temp1.c 已经从 temp2.​​c 中获取了 fun1 。我的理解有什么错误吗? “在第一个示例中,也不需要前向声明 fun1()。”当我删除声明时,它显示“在函数main', undefined reference to fun1'。你能解释一下吗?
  • @Salim,您的评论促使我重新检查问题和我的答案,并对您的具体示例的分析进行实质性修改。您应该会发现更改已清楚标记。
  • 所以第一种情况下的内联函数(具有内联定义)的行为类似于静态内联函数。如果我们在同一个 TU 中有一个内联声明,我们可以这样得出结论吗?
  • 在第一种情况下,我们可以在哪里或以什么方式有效地使用内联函数?
  • @Salim,是的,函数的真正内联定义具有类似于静态函数定义的属性。特别是,这两种函数定义都不是外部定义。
猜你喜欢
  • 2018-04-25
  • 2012-02-16
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
  • 2018-08-18
  • 2015-12-31
  • 2021-05-12
  • 1970-01-01
相关资源
最近更新 更多