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 中可用的所有编译时运算符吗 C 中有两个运算符 无论操作数如何 它们的结果始终可以在编译时确定 它们是sizeof 1 and 2 当然 其他运算符的许多特殊用途可以在编译时解决 例如标准中列出的那些整数常量表达式 1 与
  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 通过 CMIS (dotCMIS) 连接到 SP2010:异常未经授权

    我正在使用 dotCMIS 并且想要简单连接到我的 SP2010 服务器 我尝试用 C 来做到这一点 如下所示http chemistry apache org dotnet getting started with dotcmis htm
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • while 循环中的 scanf

    在这段代码中 scanf只工作一次 我究竟做错了什么 include
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低

随机推荐

  • 在 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