首页 > 解决方案 > 编译文件过大【202493852字节】在线提交报错

问题描述

在使用二维数组时,我尝试使用静态数组将 -1 分配给它的第一个元素:

int dp[5001][5001] = {-1};   //setting dp[0][0] to -1
int calc(int i, int j){
    //Some operations are happening here which utilize dp array.
}
int main(){
   cout << calc(0,0);
}

当我将此代码片段作为解决方案在线提交时,我得到Can't compile file: Compiled file is too large [202493852 bytes].

但是,当我尝试通过在 main() 中设置 dp 的值时

int dp[5001][5001];
int calc(int i, int j){
    //Some operations are happening here which utilize dp array.
}
int main(){
   dp[0][0] = -1;
   cout << calc(0,0);
}

上面的代码片段被成功接受并编译。

有人可以解释为什么会这样吗?

标签: c++

解决方案


当您使用初始化器声明静态数组时,例如

int dp[5001][5001] = {-1};

整个数组被放入可执行文件的数据部分。它的大小是 (5001×5001=25010001) ×sizeof(int)你的编译器。如果sizeof(int)==8,则以字节为单位的数组大小 200080008 接近您引用的限制。最后,二进制文件中还有其他内容。

另一方面,第二个示例中没有初始化器的数组

int dp[5001][5001];

在可执行文件中没有分配任何数据空间;相反,只有一条小记录告诉加载程序在启动时在进程的地址空间中分配一个此大小的零初始化内存块。

这种优化不是强制性的,但 ELF 和 Windows PE 二进制文件都使用它。初始化的数据段通常被调用.data,而未初始化的.bss


一个小小的动手实验来展示这个概念¹:

// Save me as bss.cc
int without_initializer[10000][10000];      // 100 million elements.
int with_initializer[1000][1000] = { 42 };  // 1 million elements.

/*
Run and see:
$ c++ -c -o bss.o bss.cc
$ ls -l bss.o
-rw-r--r-- 1 kkm kkm 4001008 2021-05-18 06:00:19 bss.o
$ objdump -h bss.o
bss.o:     file format elf64-x86-64
Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000000  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         003d0900  0000000000000000  0000000000000000  00000040  2**5
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          17d78400  0000000000000000  0000000000000000  003d0940  2**5
                  ALLOC
  3 .comment      0000001d  0000000000000000  0000000000000000  003d0940  2**0
                  CONTENTS, READONLY
$ rm bss.cc bss.o
*/

.data部分的大小为 0x3d0900=4000000 字节。显然,这个编译器sizeof(int)是 4。它也有LOAD标志,这意味着它必须从文件中加载,正如链接答案中很好解释的那样。

ls(1) 显示目标文件大小仅比相同的 4000000 字节大一点,标题和小.comment部分占用了一些额外空间,可能识别编译器(objdump(1) 可以转储其内容,如果你很好奇)。

.bss部分的大小为 0x17d78400=400000000,完全相等sizeof(without_initializer)。它有一个ALLOC标志告诉加载器它必须在进程的地址空间中,但没有LOAD标志,这意味着没有什么可以从文件中加载。

您可能会注意到该.bss部分在文件中恰好占用 0 个字节:它的偏移量和以下.comment部分的偏移量都是 0x003d0940。

¹ 使用 Linux 命令及其 ELF 格式。在 Windows 上,如果您手边有 Visual Studio ,请从本机工具命令提示符cl /c bss.cc使用then 。dumpbin /headers bss.obj


推荐阅读