内联函数中的静态变量

2023-11-22

我有一个在头文件中声明和定义的函数。这本身就是一个问题。当该函数未内联时,使用该标头的每个翻译单元都会获得该函数的副本,并且当它们链接在一起时会出现重复。我通过使函数内联来“修复”这个问题,但恐怕这是一个脆弱的解决方案,因为据我所知,编译器不保证内联,即使您指定“inline”关键字也是如此。如果这不正确,请纠正我。

不管怎样,真正的问题是,这个函数内的静态变量会发生什么?我最终会得到多少份?


我猜你在这里遗漏了一些东西。

静态函数?

将函数声明为静态将使其“隐藏”在其编译单元中。

具有命名空间范围 (3.3.6) 的名称具有内部链接,如果它是

— 显式声明为静态的变量、函数或函数模板;

3.5/3 - C++14 (n3797)

当名称具有内部链接时,它所表示的实体可以被同一翻译单元中其他范围的名称引用。

3.5/2 - C++14 (n3797)

如果您在标头中声明此静态函数,则包括此标头的所有编译单元都将拥有自己的该函数的副本。

问题是,如果该函数内部有静态变量,则包含此标头的每个编译单元也将有自己的个人版本。

内联函数?

将其声明为内联使其成为内联的候选者(现在在 C++ 中这没有多大意义,因为编译器会内联或不内联,有时会忽略关键字 inline 存在或不存在的事实):

带有内联说明符的函数声明(8.3.5、9.3、11.3)声明内联函数。内联说明符向实现表明,在调用时函数体的内联替换优先于通常的函数调用机制。不需要实现在调用时执行此内联替换;然而,即使省略此内联替换,仍应遵守 7.1.2 定义的内联函数的其他规则。

7.1.2/2 - C++14 (n3797)

在标头中,它有一个有趣的副作用:内联函数可以在同一模块中定义多次,链接器将简单地将“它们”连接成一个(如果由于编译器的原因没有内联它们)。

对于内部声明的静态变量,标准明确规定有一个,而且只有一个:

外部内联函数中的静态局部变量始终引用同一个对象。

7.1.2/4 - C++98/C++14 (n3797)

(默认情况下,函数是外部的,因此,除非您专门将函数标记为静态,否则这适用于该函数)

这具有“静态”的优点(即它可以在标头中定义)而没有缺陷(如果不内联,它最多存在一次)

静态局部变量?

静态局部变量没有链接(它们不能在其范围之外通过名称引用),但具有静态存储持续时间(即它是全局的,但其构造和销毁遵循特定规则)。

静态+内联?

混合内联和静态将产生您所描述的后果(即使函数是内联的,内部的静态变量也不会是内联的,并且您将以与编译单元一样多的静态变量结束,包括静态函数的定义)。

回答作者的补充问题

自从我写下这个问题后,我就用 Visual Studio 2008 进行了尝试。我尝试打开所有使 VS 符合标准的选项,但我可能错过了一些。结果如下:

当函数只是“内联”时,静态变量只有一份副本。

当函数是“静态内联”时,有多少个翻译单元就有多少个副本。

现在真正的问题是事情是否应该如此,或者这是否是 Microsoft C++ 编译器的特性。

所以我想你有类似的东西:

void doSomething()
{
   static int value ;
}

您必须意识到,函数内部的静态变量,简单地说,是一个对除函数作用域之外的所有变量都隐藏的全局变量,这意味着只有在函数内部声明它的函数才能访问它。

内联函数不会改变任何东西:

inline void doSomething()
{
   static int value ;
}

只有一个隐藏的全局变量。编译器尝试内联代码的事实不会改变只有一个全局隐藏变量的事实。

现在,如果您的函数被声明为静态:

static void doSomething()
{
   static int value ;
}

那么它对于每个编译单元都是“私有”的,这意味着每个 CPP 文件(包括声明静态函数的标头)都将拥有该函数自己的私有副本,包括其自己的全局隐藏变量的私有副本,因此变量数量为有包括标头在内的编译单元。

将“内联”添加到内部包含“静态”变量的“静态”函数:

inline static void doSomething()
{
   static int value ;
}

就内部的静态变量而言,与不添加此“inline”关键字具有相同的结果。

所以VC++的行为是正确的,你误解了“内联”和“静态”的真正含义。

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

内联函数中的静态变量 的相关文章

  • std::cout 和 std::wcout 有什么区别?

    在c 中 有什么区别std cout and std wcout 它们都控制流缓冲区的输出或将内容打印到控制台 或者它们只是相似吗 它们作用于不同的字符类型 std cout uses char作为字符类型 std wcout uses w
  • 为 Visual Studio 2013 编译 Tesseract

    我正在尝试使用tesseract在 Visual Studio 2013 中 我在链接器 gt 输入 不是 libtesseract302 static lib 中使用 libtesseract302 lib 一切都正常 并且已编译并运行
  • 启动时出现 OData v4 错误:找不到段“Whatever”的资源

    我正在构建新的 v4 服务 一切进展顺利 直到我为新模型 实体添加了新控制器 并在启动站点进行测试运行时收到此错误 控制器似乎编码正确 就像其他控制器一样 控制器 CustomersOData 中的操作 GetFeed 上的路径模板 Cus
  • 如何为 C 分配的 numpy 数组注册析构函数?

    我想在 C C 中为 numpy 数组分配数字 并将它们作为 numpy 数组传递给 python 我可以做的PyArray SimpleNewFromData http docs scipy org doc numpy reference
  • XamlReader.Load 在后台线程中。是否可以?

    WPF 应用程序具有从单独的文件加载用户控件的操作 使用XamlReader Load method StreamReader mysr new StreamReader pathToFile DependencyObject rootOb
  • 读取文件特定行号的有效方法。 (奖励:Python 手册印刷错误)

    我有一个 100 GB 的文本文件 它是来自数据库的 BCP 转储 当我尝试导入它时BULK INSERT 我在第 219506324 行上收到一个神秘错误 在解决此问题之前 我想看看这一行 但可惜的是我最喜欢的方法 import line
  • C# Dns.GetHostEntry 不返回连接到 WiFi 的移动设备的名称

    我有一个 C 中的 Windows 窗体应用程序 我试图获取列表中所有客户端的主机名 下面给出的是 ra00l 来自此链接的代码示例 GetHostEntry 非常慢 https stackoverflow com questions 99
  • Rx 中是否有与 Task.ContinueWith 运算符等效的操作?

    Rx 中是否有与 Task ContinueWith 运算符等效的操作 我正在将 Rx 与 Silverlight 一起使用 我正在使用 FromAsyncPattern 方法进行两个 Web 服务调用 并且我想这样做同步地 var o1
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • PlaySound 可在 Visual Studio 中运行,但不能在独立 exe 中运行

    我正在尝试使用 Visual Studio 在 C 中播放 wav 文件 我将文件 my wav 放入项目目录中并使用代码 PlaySound TEXT my wav NULL SND FILENAME SND SYNC 我按下播放按钮 或
  • 上下文敏感与歧义

    我对上下文敏感性和歧义如何相互影响感到困惑 我认为正确的是 歧义 歧义语法会导致使用左推导或右推导构建多个解析树 所有可能的语法都是二义性的语言是二义性语言 例如 C 是一种不明确的语言 因为 x y 总是可以表示两个不同的事物 如下所述
  • 将 log4net 与 Autofac 结合使用

    我正在尝试将 log4net 与 Autofac 一起使用 我粘贴了这段代码http autofac readthedocs org en latest examples log4net html http autofac readthed
  • (de)从 CSV 序列化为对象(或者最好是类型对象的列表)

    我是一名 C 程序员 试图学习 C 似乎有一些内置的对象序列化 但我在这里有点不知所措 我被要求将测试数据从 CSV 文件加载到对象集合中 CSV 比 xml 更受青睐 因为它更简单且更易于人类阅读 我们正在创建测试数据来运行单元测试 该集
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • 有没有办法强制显示工具提示?

    我有一个验证字段的方法 如果无法验证 该字段将被清除并标记为红色 我还希望在框上方弹出一个工具提示 并向用户显示该值无效的消息 有没有办法做到这一点 并且可以控制工具提示显示的时间 我怎样才能让它自己弹出而不是鼠标悬停时弹出 If the
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • 线程和 fork()。我该如何处理呢? [复制]

    这个问题在这里已经有答案了 可能的重复 多线程程序中的fork https stackoverflow com questions 1235516 fork in multi threaded program 如果我有一个使用 fork 的
  • 如何将 Roslyn 语义模型返回的类型符号名称与 Mono.Cecil 返回的类型符号名称相匹配?

    我有以下代码 var paramDeclType m semanticModel GetTypeInfo paramDecl Type Type Where paramDeclType ToString returns System Col
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个
  • 在客户端系统中安装后桌面应用程序无法打开

    我目前正在使用 Visual Studio 2017 和 4 6 1 net 框架 我为桌面应用程序创建了安装文件 安装程序在我的系统中完美安装并运行 问题是安装程序在其他计算机上成功安装 但应用程序无法打开 edit 在客户端系统中下载了

随机推荐

  • Windows Mobile 应用程序中 DataGrid 的列宽

    我在尝试调整数据网格列的宽度时遇到问题 我使用了发布的答案here 但我无法解决它 我使用对象列表作为数据源 在这个简单的示例中 我刚刚创建了一个智能设备应用程序 并添加了一个数据网格 那么我的代码是这样的 public Form1 Ini
  • Winforms 数据绑定:可以使用 TypeConverter 代替 Format/Parse 事件吗?

    在 Winforms 表单中 我想在输入字段包含无效值时向用户提供视觉提示 为此 我想绑定ForeColor输入字段标签的属性 布尔值 IsPropertyValid底层模型的属性 使得标签在以下情况下变为红色 IsPropertyVali
  • 现场未显示欧元符号

    我的一个字段 latin1 swedish ci 似乎在 PHPMYADMIN 字段内显示了欧元符号 然而 当我尝试在我网站上的表单输入字段中回显它时 它在 Firefox 中显示为问号 这是 html php sql mysql quer
  • 如何将XML数据转换为data.frame?

    我正在努力学习RXML包裹 我正在尝试从 books xml 示例 xml 数据文件创建 data frame 这是我得到的 library XML books lt http www w3schools com XQuery books
  • MySQL 中的 UTF8 字符串比较

    我们在 MySQL 5 中遇到有关大小写和重音的 utf8 字符串比较问题 根据我收集的信息 MySQL 通过考虑 字符组应该被视为相等 来实现排序规则 例如 在utf8 unicode ci排序规则中 所有字母 E e 都在同一个框中 以
  • 在 Android 操作系统中将 JPEG/PNG 图像转换为 TIFF 图像格式

    我正在开发一个应用程序 其中需要 TIFF 格式的图像 但在 Android 中 您可以将位图 图像转换为仅 JPEG PNG 图像 有没有在android上将JPEG PNG文件转换为TIFF格式的好方法 Android 不支持 java
  • matplotlib 颜色条的位置和大小

    我在用着quadmesh创建一个简单的极坐标投影图 这是一个最小的脚本 它基本上产生了我想要做的事情 from future import unicode literals import numpy as np import matplot
  • .NET 有 XmlEncode / XmlDecode 吗?

    有没有方法encoding and decoding XML在 NET 中 我似乎无法找到它们 并且想知道为什么它们不存在以及可以使用什么来代替 我需要对 XML 文档进行编码并将其传递给 Web 服务上的字符串参数 然后需要在另一端对其进
  • 检查 WPF DataGrid 单元是否有错误

    我在单元格上设置了验证 它按预期工作 在文本框周围放置红色突出显示并添加带有错误的工具提示 但是 如果我尝试访问 Validation GetHasError TheGrid 其中 TheGrid 是我的 DataGrid 它始终为 fal
  • 如何防止Web服务API中的并发?

    我们有三个网络服务 a b c 其中每个服务映射到一个方法 go 在一个单独的 Java 类中 ClassA ClassB ClassC 同一时间只能运行一项服务 即 b无法运行 a在跑 然而 由于这是一个 REST API 因此无法阻止客
  • 调试区域中显示的信息过多 - Xcode 8

    我刚刚升级到 Xcode 8 在构建和运行我的项目时 大量信息被打印到调试区域 这是一个示例 016 09 14 08 37 54 394736 SmartTapp 8645 112431 子系统 com apple network 类别
  • 与 getDerivedStateFromProps 中之前的 prop 进行比较

    想象一个具有 prop name 和 state elapse 的组件 new Component name gt Hi name It s been elapse seconds elapse 当 prop 时应重置为 0 name 变化
  • Java 导入与代码性能

    我想知道我是否包含了很多import在我的java程序中 它会影响我的代码的性能 例如 程序会变慢 背后的逻辑是import在Java中与include in C 它会影响我的代码的性能 例如 程序会变慢 不 它不会影响代码的性能 二进制文
  • 测量docker容器的执行时间

    我有一个名为my image启动命令并关闭 使用命令在容器中运行图像时docker run rm my image 是否可以测量容器的执行时间 Edit 我需要在容器执行后查看这些计时信息 因此我无法使用time命令 我以某种方式希望找到
  • 如何统计java中执行的字节码数量

    我要参加麻省理工学院的战斗代码竞赛 参赛者编写程序来控制互相战斗的机器人 问题是你的机器人每次只能执行一定数量的字节码 去年是每轮 10000 个 现在 一个简单的循环 喜欢 int i 0 i lt 100 i do nothing 根据
  • 在 C++ 中,类模板的显式特化定义应该放在哪里?

    根据 温度规格 5 对于给定的模板和给定的一组模板参数 一个明确的专业化在程序中最多定义一次 根据 基本 def odr and 类模板的显式 完整 特化的定义不能放在标头中 否则包含该标头的每个翻译单元中都有一个定义 因此整个程序中将有多
  • 如何在(子)模块中使用 __init__.py 定义命名空间?

    我的问题是关于编写 Python 3 x 包和 子 模块以及正确使用 init py文件来声明命名空间 我曾经用 C 编写代码 所以我喜欢使用很多单独的文件来组织项目 例如 imo 如果一个模块包含多个类 则每个类都应该位于单独的文件中 由
  • 安装和更新 Perl 模块为“通用”(x86_64、arm64)?

    是否可以安装和更新具有通用 x86 64 arm64 架构支持的 Perl CPAN 模块 如果是 那么如何 背景 在基于arm的macOS计算机上 可以为一个指定的架构安装Perl CPAN模块 如下所示 sudo cpan i Enco
  • WebStorm 和 PHPStorm 的区别

    我正在选择一个用于 Web 开发的 IDE 我想知道 WebStorm 和 PHPStorm 之间的区别是什么 我在 JetBrains 的网站上找不到任何要点 甚至 Google 也没有多大帮助 我现在所知道的是 PHPStorm 不像
  • 内联函数中的静态变量

    我有一个在头文件中声明和定义的函数 这本身就是一个问题 当该函数未内联时 使用该标头的每个翻译单元都会获得该函数的副本 并且当它们链接在一起时会出现重复 我通过使函数内联来 修复 这个问题 但恐怕这是一个脆弱的解决方案 因为据我所知 编译器