编译器可以将函数范围的、非静态的 const 数组存储在常量数据中并避免每次调用初始化吗?

2024-04-23

读书中字符数组/字符串如何存储在二进制文件(C/C++)中? https://stackoverflow.com/q/71932148/364696,我在思考原始字符串涉及的各种方式,"Nancy",将在生成的二进制文件中完好无损地显示。那个帖子的案例是:

int main()
{
    char temp[6] = "Nancy";
    printf("%s", temp);

    return 0;
}

显然,在一般情况下(编译器无法确认是否temp是未突变的),它实际上必须初始化一个堆栈本地数组以允许将来的突变;数组本身必须分配空间(在堆栈上,或者可能使用寄存器来实现真正奇怪的架构),并且必须在每次调用函数时填充它(让我们假设这不是main在 C++ 中仅调用一次,并且通常在 C 中仅调用一次),以避免重入问题等。是否将初始化硬编码到程序集中,或者执行memcpy与程序的常量数据部分无关;肯定有一些东西必须在每次调用时初始化。

相比之下,如果char temp[6] = "Nancy";被替换为以下任意一项:

  1. const char *temp = "Nancy";
  2. char *temp = "Nancy";(仅限 C;在 C++ 中,文字为const char[],尽管实际上它们在 C 中也不可变)
  3. static const char temp[6] = "Nancy";
  4. static char temp[6] = "Nancy";

那么程序不需要在每次调用时分配任何基于数组长度的资源(在情况 #1 和 #2 中只需分配一个指针变量),并且在除情况 #4 之外的所有情况下,它都可以将只读内存中的数据放入烘焙到二进制文件的数据常量(#4 会将其放入读写内存部分,但它仍然可以烘焙到二进制文件中并加载写入时复制)。

我的问题:标准是否提供了余地const char temp[6] = "Nancy";行为等同于static const char temp[6] = "Nancy";?两者都是不可变的,修改它们是违反规则的。我知道的唯一区别是:

  1. Without static,您希望数组的地址与其他本地地址位于同一位置,而不是位于程序内存的其他部分(可能会影响缓存性能)
  2. Without static,从技术上讲,您是说变量在每次调用时创建和销毁

我没有看到任何明显的问题可观察到的标准行为:

  • 除了未定义的行为之外,您无法观察数组的存在和停止存在,例如返回一个指向temp,在没有保证的情况下
  • 你不能合法地计算ptrdiff_t对于不相关的变量(仅在给定数组内,加上所述数组的最后一位虚拟元素)

so I'd think编译器可以安全地“视为static对于这种情况,按照假设规则;没有办法观察差异,所以它可以做任何它感觉最好的事情。

我是否遗漏了 C 或 C++ 标准所缺少的任何内容require某种每次调用的初始化const但非static函数作用域数组?如果 C 和 C++ 标准不一致,我也想知道。

Edit:正如 Barmar 在常量中指出的那样,有标准合法的方法来检测这种行为在特定的编译器中, e.g.:

int myfunc() {
    const char temp[6] = "Nancy";
    const char temp2[6] = "Nancy";
    return temp == temp2;  // true if compiler implicitly made them static or combined them, false if not
}

or:

int otherfunc(const char *s) {
    const char temp[6] = "Nancy";
    return s == temp;
}

int myfunc() {
    const char temp[6] = "Nancy";
    return otherfunc(temp); // true if compiler implicitly made them shared statics, false if not
}

该标准没有规定局部变量是如何实现的。堆栈是一种常见的选择,因为它使递归函数变得容易。但是叶子函数很容易检测,并且这个例子几乎是一个精确携带副作用的叶子函数printf.

对于此类叶函数,编译器可能选择使用静态分配的内存来实现局部变量。正如问题所正确指出的那样,局部变量仍然需要构造和销毁,因为它们不是静态的。

然而,在这个问题上,char temp[6]没有构造函数或析构函数。因此,如所描述的在叶函数中实现局部变量的编译器将具有memcpy初始化temp.

This memcpy对优化器来说是可见的 - 它会看到全局地址,这是同一地址的唯一使用printf,然后可以推断出每个memcpy可以移至程序启动。重复调用相同的memcpy是幂等的并且可以被优化掉。

这将导致生成的程序集与static案件。所以问题的答案是肯定的。编译器确实可以生成相同的代码,甚至有一种似乎合理的方式最终可以实现这一点。

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

编译器可以将函数范围的、非静态的 const 数组存储在常量数据中并避免每次调用初始化吗? 的相关文章

  • 如何在 php 数组中添加条件?

    这是数组 anArray array theFirstItem gt a first item if True conditionalItem gt it may appear base on the condition theLastIt
  • 未初始化成员的警告在 C++11 上消失

    我编译这个简单的程序 include
  • 在长时间运行期间发送 Windows 消息?

    我在运行的大型操作中收到以下消息 CLR 无法转换 从 COM 上下文 0x1fe458 到 COM 上下文 0x1fe5c8 60 秒 这 拥有目的地的线程 上下文 公寓最有可能 要么进行非抽水等待 要么 处理很长时间的运行 无需泵送 W
  • C 程序的“编译器正确”命令

    这是关于中提到的编译步骤Linux 期刊文章 https www linuxjournal com article 6463 C 程序是使用编译的cpp cc1 as and ld该文章中的命令 我能够执行这些步骤cpp as and ld
  • C# 字典循环增强

    我有一本包含大约 100 万个条目的字典 我不断地循环字典 public void DoAllJobs foreach KeyValuePair
  • 同步和异步 API

    我正在开发一个库 它提供一些耗时的服务 我需要每个 API 有两个版本 一个用于同步函数调用 另一个用于异步 图书馆用户应决定使用哪个版本 服务结果可能对于系统继续运行 同步调用 至关重要 可能需要在不同的工作线程中完成相同的操作 因为结果
  • 如何查看某个函数以 3 秒的间隔被调用了多少次?

    我想检查我的函数在 3 秒内可以运行多少次 我写了这段代码 include
  • Compact Framework 3.5 上的 System.Data.SQLite 问题

    我在我的紧凑框架应用程序中使用 sqlite 来记录系统中的事件 我也在使用系统 数据 SQLite http sqlite phxsoftware com 该事件具有描述其发生时间的时间戳 我将此时间戳记作为刻度存储在我的表中 除此列外
  • C++ 标准是否保证未使用的私有字段会影响 sizeof?

    考虑以下结构 class Foo int a 在 g 中测试 我明白了sizeof Foo 4但这是由标准保证的吗 是否允许编译器注意到a是一个未使用的私有字段并将其从类的内存表示中删除 导致更小的 sizeof 我不希望任何编译器真正进行
  • 仅使用 url 嵌入视频

    给定一个 youtube url 我如何使用 net c 将视频嵌入到页面中 只需添加如下一行 将 autoplay 设置为 0 或 1 取决于您是否希望人们真正留在您的页面上
  • 企业库 CacheFactory.GetCacheManager 抛出空引用

    我正在尝试将使用 1 1 版本的企业库缓存块的应用程序转换为 2 0 版本 我认为我真正遇到的问题是不同 EntLib 部分的配置被分成几个文件 显然 这曾经是由ConfigurationManager 部分处理程序 但现在已经过时 取而代
  • 在库中使用 .Net Standard 1.4 并在应用程序中使用 .Net Framework 4.6.1 时,无法加载文件 System.IO.FileSystem,版本=4.0.1.0

    我有一个包含一个库和两个应用程序的解决方案 这些应用程序代表同一个程序 其中一个针对通过 UAP10 的 Windows App Store 构建 另一个针对使用 Net Framework 4 6 1 的 Microsoft Window
  • 如何使用 jq 对可能不存在的数组进行排序?

    给定以下 JSON alice items foo bar bob items bar foo charlie items foo bar 我可以排序items数组如下 jq lt users json map items sort ite
  • HTTP 错误 500.35 - ANCM 同一进程中的多个进程内应用程序 ASP.NET Core 3

    从今天早上开始 没有对项目代码进行任何更改 一个非常简单的 Web API 一个控制器和 3 个方法 使用 Swagger 它不再启动 我收到错误 HTTP 错误 500 35 ANCM 同一进程中有多个进程内应用程序 事件查看器报告最无用
  • 显示具有相同节点值的多个 XML 数据条目

    我有一个 XML 文档 其中包含课程信息 如下所示
  • 我试图使这段代码递归,但由于某种原因它不起作用[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我试图使这
  • 使用 MVVM 绑定 Xamarin.Forms 中的属性

    我在使用 Xamarin Forms 和 MVVM 制作游戏时遇到问题 游戏中有一艘由用户控制的潜艇 并且有水雷掉落 因此用户必须避开这些水雷 这些地雷是在运行时使用 2 个计时器生成的 因此我用 XAML 中的 CollectionVie
  • 多线程文件写入

    我正在尝试使用多个线程写入大文件的不同部分 就像分段文件下载器所做的那样 我的问题是 执行此操作的安全方法是什么 我是否打开文件进行写入 创建线程 将 Stream 对象传递给每个线程 我不希望发生错误 因为多个线程可能同时访问同一个对象
  • C# StreamReader 使用分隔符保存到数组

    我有一个文本文件 其中包含制表符分隔的数据 我在 C 应用程序中需要的是从文本文件中读取一行并将它们保存到一个数组中 在每个位置将它们分开 t 然后我对下一行做同样的事情 My code StreamReader sr new Stream
  • 通过网络共享的 SQL CE

    我之前见过这个问题 但找不到关于什么是可能 不可能以及什么解决方法可能可用的明确解释 我有一个现有的 C 应用程序 它使用 SQL CE 来存储本地信息 该数据库只能由单个应用程序访问 并存储在用户的 appdata 文件夹中 某些环境将

随机推荐