C 中的静态和外部内联函数[重复]

2024-05-06

我正在尝试详细了解静态函数和外部函数之间的区别。

我知道静态内联函数和外部内联函数之间的基本区别。

我的理解如有错误请指正:

  • 静态内联函数仅对定义它的翻译单元可见。
  • 外部内联函数可以在多个翻译单元中访问。
  • 最好在头文件中定义内联函数
  • 静态和静态内联函数定义之间没有区别。

下面是一个示例代码,我对这种行为感到困惑。

file1.c

#include <stdio.h>
#include "file.h"

int main(void)
{
  fun1(); 
  return 0;  
}

static inline void fun1(void)
{
  int i;
  for (i = 0; i < 10; i++) {
      static int k = 20;
      printf("Value : %d \n", k++);
  }
}

file2.c

#include <stdio.h>

inline void fun1(void)
{
  int i;
  int k = 0;
  for (i = 0; i < 10; i++) {
      printf("Value : %d \n", k++);
  }
}

file.h

#ifndef FILE_H
#define FILE_H 

extern inline void fun1(void);

#endif

当我编译上面的代码“gcc file1.c file2.c”时,从file2.c调用fun1。这很清楚,因为 fun1 被声明为 extern,它应该采用 file2.c 中的 extern 函数(默认情况下所有内联函数都是 extern ?)。

但是当我将 file1.c 中的静态内联函数更改为静态函数(static void fun1(void)) 时,从 file1.c 调用 fun1 。可能是什么原因 ?

我还读到“如果使用外部链接声明内联函数但未在同一翻译单元中定义,则行为未定义”。但我不明白这一点。可以用上面的例子来解释吗?

与 C 相比,C++ 中的静态函数和外部函数有什么区别吗?


您的代码不正确,因为您无法使用以下方式声明函数extern(这是默认的)然后提供一个static定义。它能编译的事实并不表明有什么用处。

从 n1548 §6.2.2 开始:

如果在翻译单元内,相同的标识符同时出现在内部和外部链接中,则行为未定义。

所以,你会得到这样的东西file1.c:

// Has external linkage (which is the default!)
extern inline void fun1(void);

// This would also have external linkage.
inline void fun1(void);

// This has static linkage.
static inline void fun1(void) {
    ...
}

(注:“外部链接”是默认值,但extern inline实际上意味着一些特殊的东西,它不同于inline.)

嘭!未定义的行为。编译器甚至可能不会给您错误消息,尽管有些编译器似乎会为此提供错误消息。



error: static declaration of 'func' follows non-static declaration
  

这个错误实际上有nothing与该功能有关inline。无论有或没有,这都是一个错误inline.

那些问题呢?

静态内联函数仅对定义它的翻译单元可见。

这对所有人都是如此static功能。他们有“内部联系”,所以你可以static void func(void);在一个文件和一个完全不同的文件中static int func(char *p);在不同的文件中。这inline这里没有区别。

外部内联函数可以在多个翻译单元中访问。

是的,这就是为什么你不应该将它们放在头文件中。如果将它们放入头文件中,您将获得同一函数的多个不同定义,这些定义都可以从不同的翻译单元访问。这是一个错误。相反,将extern inline在源文件中,但它只需要是声明,而不是定义。

最好在头文件中定义内联函数

在其他地方定义内联函数没有任何实际意义。如果您的函数仅在一个文件中使用,只需标记它static编译器将决定如何调用该函数。

静态和静态内联函数定义之间没有区别。

是的,没有区别。

嗯,从技术上来说,不,是有区别的,因为编译器可以处理static inline功能与仅不同static功能。然而,现代编译器倾向于决定使用自己的一组规则来内联函数,以及函数是否是inline不会对这个过程产生太大影响。

嗯,实际上还有另一个区别。 Astatic inline如果不使用函数定义,则不会在 GCC 中生成警告,但是static函数将.这样你就可以放一个static inline头文件中的函数。这是放置的替代方法inline在头文件中,这需要你有一个extern inline在你的程序中的某个地方使用这个函数。但是,如果编译器决定不内联您的static inline函数,要么是因为它认为内联更糟糕,要么是因为内联是不可能的,那么它必须在使用该函数的每个文件中制作该函数的单独副本。

那么,如何正确地做到这一点呢?

永远不要声明函数static如果它有一个先前的非静态声明。即使编译通过,这也是一个错误。

不要声明inline extern头文件中的函数。这会为该函数创建一个“外部定义”,并且您在整个程序中只能拥有其中之一。

不声明inline头文件中的函数而不定义它们。无关紧要。

以下是您想要执行此操作的方式:

In mylib.h:

// Provide "inline definition" of the function.
inline int times_two(int x) {
    return x * 2;
}

In mylib.c:

#include "mylib.h"

// Provide "external definition" of the function.
extern inline int times_two(int x);

这是自 C99 以来的标准处理方式。编译器应该可以自由地使用内部定义或外部定义,无论它认为哪一个更好。如果您没有外部定义或有多个外部定义,则可能会出现链接错误,就像常规函数一样。

C++ 对于内联函数有自己完全不同的规则。

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

C 中的静态和外部内联函数[重复] 的相关文章

随机推荐

  • 如何将typescript添加到Vue 3和Vite项目中

    我的设置 我通过以下方式安装了 Vue 和 Vite创建 vite 应用程序模块 然后将 init vite app 生成的所有包更新为 Vue 和 Vite 的最新 RC 版本 现在我想对我的所有代码使用打字稿 首先我只是玩了一下 然后添
  • 横切关注点示例

    什么是一个很好的例子cross cutting concern 医疗记录示例维基百科 http en wikipedia org wiki Cross cutting concern页面对我来说似乎不完整 具体来说 从这个例子来看 为什么日
  • 规范注册 ID 和消息 ID 格式

    我的理解有问题Canonical Registration Id并让谷歌返回它 我特意注册了两次我的Android应用程序 以测试Canonical Registration Id 但是当我尝试向两者推送消息时Registration Id
  • 为什么需要为每个线程创建 ABAddressbookRef?

    苹果说 重要提示 ABAddressBookRef 的实例不能被多个使用 线程 每个线程必须创建自己的实例 But why 我知道某些特定的类或操作必须在主线程中完成 而且我知道有些对象不是线程安全的 这意味着如果这些对象同时被两个不同的线
  • 创建一个跨浏览器 mixin 进行转换:旋转

    我想为 sass 创建一个 mixin 它将对指定元素应用旋转 mixin 应采用一个参数 表示要应用的旋转度数 从 css3please com 我找到了一种使用 CSS 实现此功能的跨浏览器方法 box rotate moz trans
  • 如何从特定 Sourceforge 项目下载所有文件?

    在花了大约一个小时从 sourceforge 下载几乎每个 Msys 包之后 我想知道是否有更聪明的方法来做到这一点 是否可以使用 wget 来实现此目的 我已经成功地使用了这个脚本 https github com SpiritQuadd
  • 文件/文件夹结构的递归搜索

    我正在尝试为返回文件和文件夹列表的 Web 服务构建递归搜索功能 我创建了这两个方法 因此它们充当递归搜索 它首先获取顶级内容 然后将任何文件添加到 fileList 并将任何子文件夹添加到 subFoldersList 我们传入访问级别
  • 无限滚动 jQuery 和 Laravel 5 分页

    我成功从控制器返回数据 public function index posts Post with status verified gt paginate 30 return view show gt with compact posts
  • 使用 PSEXEC 远程启动和停止 Windows 服务

    如何使用 PSEXEC 远程启动和停止 Windows 服务 最好是编写语法我尝试了下面给出的 cmdlet psexec Server u Administrator p Somepassword ServiceName SysInter
  • 虚拟继承 - 跳过构造函数

    我有以下课程 class Socket Socket Socket SOCKET s class Connection public virtual Socket Connection IP ip 这两个类包含一些纯虚函数和一些非虚函数以及
  • useState 由于某种原因没有更新?

    当我尝试使用 axios 从后端 API 获取一些数据 并在由于某种原因获得结果后设置状态时 状态不会更新 当我尝试使用状态时 它只会向我显示一个空数组 但有趣的是当我console log res data 它会毫无问题地向我显示我的列表
  • 设置restrict_xpaths设置后出现UnicodeEncodeError

    我是 python 和 scrapy 的新手 将restrict xpaths 设置设置为 table class lista 后 我收到了以下回溯 奇怪的是 通过使用其他 xpath 规则 爬虫可以正常工作 Traceback most
  • 如何使您的 GWT 应用程序可插入?

    我正在 与我的团队 编写一个 GWT 应用程序 它解析并表示一些特定于领域的语言 例如 使用文本 视频和 UI 控件播放媒体演示 所以应用程序有一组组件 一个 用于保存模型 一个 用于控制例程 控制器 当然我们还有视图类 现在我们遇到了一个
  • 如何检查打开的跨域窗口是否准备好接收postmessage?

    我从另一个域启动一个 URL 然后向它发送消息 const child window open http urlfromanotherdomain com child postMessage you cant handle the mess
  • 有没有办法在 vscode 片段前缀中使用正则表达式?

    我阅读了该文档 似乎正则表达式仅在代码片段正文中使用 正则表达式只能用于转换代码片段正文中的代码片段变量 但您可以放置 多个代码片段前缀 如下所示 stripLastDirectory prefix lsd lsf lsq body TM
  • Java 中的 ConcurrentHashMap 和 Hashtable [重复]

    这个问题在这里已经有答案了 Java 中的 ConcurrentHashMap 和 Hashtable 有什么区别 哪个对于线程应用程序更有效 ConcurrentHashMap 和 Hashtable 锁定机制 Hashtable属于Co
  • 使用信用卡和支付网关进行年龄验证

    我正在开发一个游戏网站 用户必须年满 18 岁才能付款并开始游戏 我正在寻找一种解决方案来使用用户通过网站付款的信用卡来验证年龄 是否可以借助任何公认的支付网关来验证持卡人的年龄 是否可以通过任何方式验证持卡人的年龄 公认的支付网关 我 1
  • 如果应用程序被杀死,小米手机中不会收到 GCM 推送通知

    我将 GCM 集成到我的项目中以接收来自服务器的推送通知 我能够在所有设备 Nexus 三星等 中成功接收推送通知 但是 我在小米手机上收不到通知 当应用程序正在运行或在后台时 我会收到通知 但是如果我终止该应用程序 通过将应用程序从最近的
  • Python二进制数据读取

    urllib2 请求接收二进制响应 如下所示 00 00 00 01 00 04 41 4D 54 44 00 00 00 00 02 41 97 33 33 41 99 5C 29 41 90 3D 71 41 91 D7 0A 47 0
  • C 中的静态和外部内联函数[重复]

    这个问题在这里已经有答案了 我正在尝试详细了解静态函数和外部函数之间的区别 我知道静态内联函数和外部内联函数之间的基本区别 我的理解如有错误请指正 静态内联函数仅对定义它的翻译单元可见 外部内联函数可以在多个翻译单元中访问 最好在头文件中定