在内存耗尽之前我可以声明多少个 const 变量?

问题描述 投票:0回答:1

我正在编写包含大量 const 变量(主要是整数和枚举)的代码,我想知道我可以声明的变量数量是否有最大限制?我的想法是,这些 const 变量分配在堆栈上,这意味着我可以声明大约 1MB/4bytes = 250000 个变量(这足够了),假设堆栈大小为 1MB。我说得对吗?

我的意思的一个简单例子:

测试.cpp:

const unsigned int VECTOR_ID = 4;
const unsigned int MATRIX_ID = 3;

int main()
{
  std::cout << VECTOR_ID << " : " << MATRIX_ID << std::endl;
  return 0;
}
c++ stack constants stack-overflow
1个回答
4
投票

注意,编译时已知的常量可能不对应于任何对象;当您在启用优化的情况下进行编译时,常量将作为立即值直接编译到机器指令中。这里是一个简单的示例。这意味着常量变量的数量没有限制。这也意味着根本不使用的常量可能会完全消失。 (并且如果以任何不平凡的方式使用它们,代码的大小将超过数据的大小。)

即使你的常量变量确实变成了对象,例如因为它们的地址被占用,它们将被“编译到您的程序中”并成为可执行文件的一部分。

程序的大小及其段的大小受到可执行文件格式、系统资源以及可能的构建工具的限制。 Intel 页面似乎表明,即使在 64 位架构上,静态数据(全局常量可能最终出现的地方)在 Windows 下也限制为 2 GB(这仍然比您的用例大三个数量级):

请注意,静态数据和堆栈数据的限制在 32 位和 64 位变体中是相同的。这是由于 Windows 可移植可执行文件 (PE) 文件类型的格式造成的,该文件类型用于描述链接器所布置的 EXE 和 DLL。它具有用于图像部分偏移和长度的 32 位字段,并且未针对 Windows 的 64 位变体进行扩展。与 32 位 Windows 一样,静态数据和堆栈共享相同的前 2GB 地址空间。

快速搜索似乎表明现代 Linux 中不存在此限制。

独立于任何二进制限制,构建工具(编译器和链接器)可能有更多限制。即使稍后的优化器阶段消除了所有常量,仍然需要解析它们的定义。范围或翻译单元中的名称数量可能存在限制。

  • Microsoft C++ 例如,成员初始值设定项的数量限制为 6144
  • C 标准指定每个作用域至少有 511 标识符,但大多数编译器将允许更多。
  • C++20 标准(公开草案此处,数字相同)在附件 B 中规定了一些数量的推荐最小值。其中包括
    • 一个翻译单元中有 65 536 个外部标识符
    • 在一个块中声明了 1024 个具有块作用域的标识符
    • 单个类中有 16 384 个非静态数据成员(包括继承的)
    • 类的 1024 个静态数据成员
    • 单个枚举中有 4096 个枚举常量。

我刚刚创建了一个有关 C++ 程序的数据点,其中包含 200 万个外部变量和 200 万个局部变量:

  • gcc: 使用 x86_64-pc-msys gcc 13.2 成功编译。不过,我必须通过在命令行上传递
    -Wl,--stack,20000000
    来显式设置堆栈大小(这样它就变成了
    gcc -O0 -Wl,--stack,20000000 -o many2 many2.cpp
    ;20000000 是一个安全的猜测)。如果没有该设置,则会生成可执行文件,但在运行时崩溃。源代码长 101,555,599 字节,可执行文件只有 64,028,280 字节。在我相当普通的电脑上,编译需要一分钟多一点的时间。
  • MSCV: cl.exe 已经以 8% CPU(半个核心)运行了几个小时。命令行是
    cl /O0 many2.cpp

自我注意:不要指定

-Wall
,因为每个未使用的变量都会在终端上生成警告。在 msys 下的 mintty 上打印数百万行比我愿意等待的时间要长(推断,一定是几个小时)。

© www.soinside.com 2019 - 2024. All rights reserved.