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

Tha*_*ain 6 c++ stack-overflow stack constants

我正在编写具有很多 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;
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*ica 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 个枚举常量。

我刚刚创建了一个关于具有 200 万个外部变量和 200 万个局部变量的 C++ 程序的数据点:

  • 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 上打印数百万行比我愿意等待的时间要长(推断,肯定是几个小时)。