C 内联函数和“未定义的外部”错误

2023-11-27

我试图用内联函数替换一些宏子例程,以便编译器可以优化它们,以便调试器可以单步执行它们,等等。如果我将它们定义为普通函数,它就可以工作:

void do_something(void)
{
  blah;
}

void main(void)
{
  do_something();
}

但如果我将它们定义为内联:

inline void do_something(void)
{
  blah;
}

void main(void)
{
  do_something();
}

它说“错误:未定义的外部”。这意味着什么?在黑暗中刺一剑,我尝试过

static inline void do_something(void)
{
  blah;
}

void main(void)
{
  do_something();
}

并且没有更多错误。函数定义和函数调用位于同一个 .c 文件中。

有人可以解释为什么一个有效而另一个无效吗?

(第二个相关问题:如果我想在多个 .c 文件中使用内联函数,我应该将它们放在哪里?)


首先,编译器并不总是将内联函数标记为inline;例如,如果您关闭所有优化,它可能不会内联它们。

当您定义内联函数时

inline void do_something(void)
{
  blah
}

并使用该函数,即使在同一个文件中,对该函数的调用也是由链接器而不是编译器解析的,因为它是隐式“外部”的。但这个定义本身并不提供函数的外部定义。

如果您包含的声明没有inline

void do_something(void);

在一个C文件中可以看到inline定义,编译器将提供该函数的外部定义,并且错误应该消失。

原因static inline工作原理是它使函数仅在该编译单元内可见,因此允许编译器解析对该函数的调用(并对其进行优化)并在该编译单元内发出该函数的代码。然后链接器不必解析它,因此不需要外部定义。

放置内联函数的最佳位置是在头文件中,并声明它们static inline。这消除了对外部定义的任何需要,因此解决了链接器问题。但是,这会导致编译器在使用该函数的每个编译单元中发出该函数的代码,因此可能会导致代码膨胀。但由于该函数是内联的,因此它可能很小,因此这通常不是问题。

另一种选择是define it as extern inline在标头中,并在一个 C 文件中提供和extern 宣言没有inline修饰符。

gcc 手册是这样解释的:

通过声明内联函数,您可以指示 GCC 调用 该功能更快。 GCC 实现这一目标的一种方法是集成 该函数的代码放入其调用者的代码中。这使得 通过消除函数调用开销来加快执行速度;在 另外,如果任何实际参数值是常数,则它们的 已知值可能允许在编译时进行简化,这样就不会 需要包含所有内联函数的代码。对的影响 代码大小难以预测;目标代码可能更大或更小 函数内联,具体取决于具体情况。你可以 还指示 GCC 尝试将所有“足够简单”的功能集成到 他们的来电者可以选择-finline-functions.

GCC 实现了声明函数的三种不同语义 排队。一种可用于-std=gnu89 or -fgnu89-inline或者 什么时候gnu_inline属性存在于所有内联声明中, 另一个时候-std=c99, -std=c1x, -std=gnu99 or -std=gnu1x(没有-fgnu89-inline),第三个是编译C++时使用的。

要声明内联函数,请使用inline其关键字 声明,像这样:

 static inline int
 inc (int *a)
 {
   return (*a)++;
 }

如果您正在编写要包含在 ISO C90 程序中的头文件, 写__inline__代替inline.

这三种类型的内联在两种重要情况下的行为类似: 当。。。的时候inline关键字用于static函数,就像 上面的例子,当一个函数第一次声明时不使用inline关键字,然后定义为inline, 像这样:

 extern int inc (int *a);
 inline int
 inc (int *a)
 {
   return (*a)++;
 }

在这两种常见情况下,程序的行为与您一样 没有使用过inline关键字,除了它的速度。

当一个函数既是内联函数又是内联函数时static,如果所有调用 函数被集成到调用者中,函数的地址是 从未使用过,那么该函数自己的汇编代码永远不会 参考。在这种情况下,GCC实际上并不输出汇编代码 对于函数,除非您指定选项-fkeep-inline-functions。有些呼叫无法集成到各种 原因(特别是在函数定义之前的调用 不能集成,也不能在内部进行递归调用 定义)。如果存在非集成调用,则函数为 像往常一样编译为汇编代码。该函数还必须是 如果程序引用其地址,则照常编译,因为 无法内联。

请注意,函数定义中的某些用法可以使其 不适合内联替换。这些用法包​​括: 使用 varargs、alloca 的使用、可变大小数据类型的使用、计算 goto 的使用、 使用非局部 goto 和嵌套函数。 使用-Winline当函数被标记时会发出警告inline不能 被替换,并给出失败的原因。

根据 ISO C++ 的要求,GCC 考虑内部定义的成员函数 类的主体被标记为内联,即使它们不是内联 明确声明与inline关键词。你可以覆盖这个 和-fno-default-inline.

GCC 在不优化时不会内联任何函数,除非您 指定always_inline函数的属性,如下所示:

 /* Prototype.  */
 inline void foo (const char) __attribute__((always_inline));

本节的其余部分专门针对 GNU C90 内联。

当内联函数不是static,那么编译器必须 假设可能有来自其他源文件的调用;自从全球 符号在任何程序中只能定义一次,函数不能 在其他源文件中定义,因此其中的调用不能被 融合的。因此,一个非static内联函数总是 以通常的方式自行编译。

如果同时指定inline and extern在函数定义中, 那么该定义仅用于内联。在任何情况下都不是 函数是自己编译的,即使你引用它的地址也不会 明确地。这样的地址成为外部引用,就好像您 仅声明了该函数,并没有定义它。

这种组合inline and extern几乎有一个效果 宏。使用方法是将函数定义放在头文件中 包含这些关键字的文件,并放置定义的另一个副本 (不足inline and extern)在库文件中。中的定义 头文件将导致大多数对函数的调用被内联。 如果该功能仍有任何用途,它们将引用单个副本 在图书馆。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 内联函数和“未定义的外部”错误 的相关文章

  • C++ static_cast 从 float** 到 void**

    刚刚遇到这个 include
  • 强制枢轴项目在显示之前预加载

    我有一个带有多个 PivotItems 的 Pivot 其中一个包含一个画布 将其项目放置在动态位置 取决于数据 我获取数据 并且可以在用户选择该项目之前将这些项目放置在其位置 这不是第一个枢轴 但是 只有当我选择 PivotItem 时
  • 使用 CMake 编译时更改头文件位置会导致缺少 vtable 错误

    对于一个大型 C 项目 我需要从 qmake 过渡到 CMake 但是在处理一个玩具示例时 我遇到了一些我不理解的行为 示例代码具有单个头文件 当该头文件移动到子目录中时 我收到 MainWindow 类缺少 vtable 的错误 CMak
  • 为什么选项卡页正文不使用 .NET 选项卡控件进行更新?

    我在使用 C Visual Studio 2010 中的 NET TabControl 时遇到一个奇怪的问题 启动 Windows 窗体应用程序 添加一个选项卡控件和一个按钮 向两个选项卡页添加两个不同的标签 以便您可以区分它们 该按钮的作
  • 使用 ITextSharp 从内存流附加 PDF 文件时遇到问题

    我在附加内存中创建的 PDF 文件并将其附加到电子邮件模板时遇到问题 电子邮件没有任何问题 但没有附件 我不明白为什么会发生这种情况 这是该过程的完整代码 ExtendedEmailTemplate emailTemp new Extend
  • 通过 Microsoft Graph 从 Azure AD 获取组中的用户

    我正在通过 Microsoft Graph 从 AzureAD 请求用户列表 我取回了 User 对象 但它们的 MemberOf 属性始终为 null 我认为我可以使用 Expand 来专门请求该属性 虽然它不会导致错误 但它也不会填充该
  • JPG、DOC、PDF 等文件是否也编译成程序集?

    Q1 Does aspnet compiler exe将网站目录中包含的所有文件 甚至 JPG DOC 和 PDF 类型 编译成程序集 如果将图像添加到Web项目中的文件列表中 从而将它们添加到项目文件中 这些图像也会被VS编译成程序集吗
  • 在 C# 中将 Exe 文件作为嵌入式资源运行

    我有一个第 3 方 EXE 我只需要从我的 C 应用程序运行它 我的主要目标是对我的 C 文件中的第 3 方可执行文件进行版权保护 有没有更好的方法来做到这一点 我怎样才能做到这一点 首先将嵌入的可执行文件作为资源文件添加到您现有的资源文件
  • 如何在类中使用常量类变量声明常量数组?

    如何在类中使用常量类变量声明常量数组 是否可以 我不想要动态数组 我的意思是这样的 class test const int size int array size public test size 50 int main test t 5
  • 将模型和订阅密钥传递给 LuisDialog,而不是通过属性

    我正在编写一个可以说两种语言的机器人 因此 我需要使用两个单独的 LUIS 应用程序 每种语言一个 Bot Framework 中的 LuisDialog 是这样初始化的 来自 Microsoft 的示例 LuisModel c413b2e
  • 底层连接已关闭:接收时发生意外错误

    我来这里是因为我在通过 ftp 协议下载一些文件时遇到问题 这很奇怪 因为它偶尔会发生 甚至对于同一个文件也是如此 只是一个精确度 我正在下载非常大的文件 从 500 Mo 到 30Go 以下是我的函数返回的异常类型 抱歉 这是法语 Sys
  • JsonSerializer.Deserialize 失败

    考虑代码 using System using System Text Json public class Program public static void Main int id 9 string str id id var u Js
  • 为什么%c前面需要加空格? [复制]

    这个问题在这里已经有答案了 下面的代码一编译就给出了奇怪的o p main char name 3 float price 3 int pages 3 i printf nEnter names prices and no of pages
  • OpenMP while 循环中的手动同步

    我最近开始使用 OpenMP 为大学的一个项目做一些 研究 我有一个矩形且均匀分布的网格 在该网格上我使用迭代方案求解偏微分方程 因此 我基本上有两个 for 循环 网格的 x 方向和 y 方向各一个 并由 while 循环包裹以进行迭代
  • 为什么转发引用与右值引用具有相同的语法?

    我刚刚对这些 相当 新的功能做了一些研究 我想知道为什么 C 委员会决定为它们引入相同的语法 看来开发人员不必要浪费一些时间来理解它是如何工作的 而一种解决方案可以让我们思考进一步的问题 就我而言 它是从问题开始的 可以简化为 includ
  • xaml.cs 文件上的 InitializeComponent() 出现错误

    有时我会收到一个红色错误 内容如下 InitializeComponent 在当前上下文中不存在 以及我的其他变量 xaml受约束的x Name The x ClassXaml 文件中的名称空间和类名确实对应于我的xaml cs file
  • 非静态类中的静态方法有什么意义?

    我无法理解以下代码的潜在错误 class myClass public void print string mess Console WriteLine mess class myOtherClass public static void
  • C++中main函数可以调用自身吗?

    谁能告诉我下面的代码有什么问题吗 int main return main 我测试了一下 编译正确 它永远运行 幕后还有什么阴谋吗 TLDR 呼叫main导致未定义的行为 标准中使用的术语以及对程序员和编译器的影响似乎存在混淆 首先 单独的
  • Outlook 插件:从选定的日历中获取元素

    我正在创建 Outlook 加载项 我想知道如何从选定的日历中获取元素 例如 我需要从名为 myCalendar 的日历中获取所有约会项目 现在 我可以从所有日历中获取所有约会项目 谢谢你 这些额外的日历作为主日历文件夹的子文件夹提供 所以
  • C++ 中的无符号双精度?

    为什么 C 不支持无符号双精度语法 因为典型的浮点格式不支持无符号数 例如 参见此 IEEE 754 格式列表 http en wikipedia org wiki IEEE 754 2008 Formats 添加通用硬件不支持的数字格式只

随机推荐

  • 在 Eclipse 中显示方法名称和参数值的模板

    有没有办法在 Eclipse 中拥有一个模板 Java gt 编辑器 gt 模板 来生成这样的东西 debug methodName arg1 arg1 arg2 arg2 arg3 arg3 当在方法中使用时 例如 public void
  • 尝试在空对象引用上调用虚拟方法“android.text.Editable android.widget.EditText.getText()”

    我已经尝试了所有可能的情况但没有解决 需要建议 public class WolfActivity extends ActionBarActivity EditText fname ele lname ele email ele phone
  • 定义接受 Spark DataFrame 中的对象数组的 UDF?

    使用 Spark 的 DataFrame 时 需要用户定义函数 UDF 来映射列中的数据 UDF 要求显式指定参数类型 就我而言 我需要操作由对象数组组成的列 但我不知道要使用什么类型 这是一个例子 import sqlContext im
  • Django 管理中的默认过滤器

    如何更改默认过滤器选择 全部 我有一个名为status它有三个值 activate pending and rejected 当我使用list filter在 Django 管理中 过滤器默认设置为 全部 但我想默认将其设置为待处理 为了实
  • 具有动态内容的 UIScrollView

    我正在尝试实现一个UIScrollView 但是每个教程都涉及预设数量的项目 我拥有的是多个UITextField的 但文本字段的数量有所不同 基本上只要一textField包含文本 其下方会出现另一个空文本字段 允许用户填写无限数量的文本
  • 如何在 Gnome 终端中处于不同模式时更改 VIM 光标形状

    我想更改 VIM 不是 gVIM 的 光标取决于我当前所处的模式 我想要 正常和可视模式 块光标 插入和命令模式 I 光束光标 我尝试添加以下代码 vimrc但它不起作用 if has autocmd au InsertEnter sile
  • 角色/权限逐项列出?

    我已经寻找了一段时间 并手动完成了许多角色和权限的部署 但是有没有办法在 Sitecore 中为角色 权限创建一个包 或等效的包 当您无法选择从一个环境到下一个环境进行完整部署时 手动部署具有权限的新角色是一项非常乏味的工作 只是好奇是否有
  • 如何从 android 中的 firebase 获取子值的子值?

    如何获取ZNAME值 最初我需要比较密钥 例如 这里 ZONE 1 然后需要获取 ZNAME 提前致谢 要访问数据库中的值 您需要创建一个DatabaseReference对于那个位置 以下是对数据库中位置的三个引用 DatabaseRef
  • BC30560:“ExtensionAttribute”在命名空间“System.Runtime.CompilerServices”中不明确

    我有 asp net 项目 在 net 2 0 中 并将项目转换为 net 4 0 成功构建项目后 我在浏览器上启动网站 它抛出如下错误 编译错误 资源编译期间发生错误 需要满足此请求 具体请查看以下内容 错误详细信息并适当修改您的源代码
  • 用于查找曲线段的霍夫变换

    霍夫变换可用于从图像中提取线条 它还可以用于提取曲线 但这有点困难 因为更高维的霍夫变换会消耗资源 我想知道如何将霍夫变换限制为 3 阶曲线的 2D 投票空间 即 x 3 ax 2 bx c 任何人都知道有什么好的网站可以解释这一点 似乎找
  • 对 python 数组中的日期进行排序

    如何在 python 2 4 上对以下日期数组进行排序 timestamps 2011 06 2 2011 08 05 2011 02 04 2010 1 14 2010 12 13 2010 1 12 2010 2 11 2010 2 0
  • Python中负股息的模[重复]

    这个问题在这里已经有答案了 一直在寻找其他答案 我仍然不明白 python 中负数的模数 例如 df 的回答 x x y y x y 所以 2 5 2 2 5 5 3 是有道理的 这不是 2 2 5 5 0 还是我疯了 具有负值的模运算 奇
  • AWS批处理-如何限制并发作业的数量

    我正在寻找一种方法 通过保留队列中的剩余作业来限制正在运行的批处理作业的数量 aws批处理可以吗 限制最大vcpu数量队列所绑定的托管计算环境的数量将有效限制在该队列上同时运行的批处理作业的数量 但是 需要注意的是 如果您有其他队列共享此计
  • 对象与 DesignData 中的目标类型不匹配

    我将把它扔掉 以防有人以前遇到过这种情况 创建在 WPF 设计器中使用的 DesignData 时 出现以下两个错误之一 对象与目标类型不匹配 在 System Reflection RuntimeMethodInfo CheckConsi
  • jQuery $.ajax,错误处理程序不起作用

    您好 我注意到这个简单的代码无法按预期的方式工作 function test ajax url test GameConfiguration json dataType json data a aaa cache false method
  • 在android中比较两个声音

    我正在开发一个语音消息应用程序 我需要比较两个语音 例如 通过录制您的声音注册应用程序 已发送语音消息至 另一个用户通过录制语音 但首先需要比较这个语音 到配置文件中录制的声音 出于安全目的 需要知道录制的消息是否来自特定用户 我试过 在
  • PHP_AUTH_USER 未设置?

    由于某种原因 其中没有任何代码 if isset SERVER PHP AUTH USER isset SERVER PHP AUTH PW When the above is set the code that is here will
  • 当域规则无效时,put 方法上的其余服务的 http 响应代码是什么

    当使用 PUT 方法更新资源 并且请求包含一些会使域规则无效的数据时 返回的最合适的响应代码是什么 例如 客户资源必须具有name指定的 如果代理尝试在不提供 PUT 的情况下发出 PUTname我不想更新资源 我想告诉调用者他们需要提供一
  • Cassandra如何选择发送请求的节点?

    想象一下 Cassandra 集群需要由客户端应用程序访问 在Java api中 我们创建一个集群实例并通过会话发送读取或写入请求 如果我们使用读 写一致性 ONE API 如何选择实际节点 协调节点 来转发请求 是随机选择的吗 请帮忙解决
  • C 内联函数和“未定义的外部”错误

    我试图用内联函数替换一些宏子例程 以便编译器可以优化它们 以便调试器可以单步执行它们 等等 如果我将它们定义为普通函数 它就可以工作 void do something void blah void main void do somethi