编译器如何在 C 中将数组初始化(为零)?

How are arrays initialised (to zero) in C by the compiler?

免责声明:我可能误解了数组是如何创建、分配和初始化的。如果是这样,请尝试在字里行间阅读。

如果我通过

创建一个数组
int array[15] = {0};

array 的所有元素,编译器会将元素初始化为0。编译器是如何完成的?编译器是否插入一个循环来迭代分配的内存并将每个元素设置为零?大小会影响性能吗? IE。初始化双倍大小 (30) 的数组是否需要更长的时间?还有多久?双倍的?对数? 2 的幂?

只是好奇才问。

在 C 中,编译器通常对本地定义的数组使用标准 C 函数 memset

P.S。 例如,如果我没记错的话,在 IBM 大型机中,函数 memset 是用两条 mashine 指令实现的,例如 MVI 和 MVCL,并且可以内联。说实话我已经不记得了。如果您感兴趣,您应该查看由 IBM XL C++ 编译器生成的目标代码。

我猜,你说的是全局 variables/arrays。

实际上,这不是编译器任务(如果我们谈论的是现代操作系统)。编译器只是将此对象标记为零初始化。

然后,链接器将此对象放入应该用零初始化的部分。在 ELF 中,这个部分被命名为 .bss。通常,这部分没有数据(因为只有零),但它有大小。

然后,当加载程序将您的程序加载到内存中时,它知道应该将属于 .bss 部分的内存归零。

如果我们谈论的是基于堆栈的(局部)变量,那么编译器只调用 memset()

在大多数 OSes 上,静态或全局数组通过将它们放入可执行文件的 bss(块存储 space)部分来初始化为零。当 OS 加载可执行文件时,归零内存映射到 BSS 地址(有足够的页面覆盖可执行文件存储在其 ELF header 中的 bss 大小,或 [=34] 的任何可执行文件格式=] 使用。)

如果您有一个 non-zero 初始值设定项,即使是数组中的一个值,那么整个事情都必须放在 data 部分中。 (或者 rodata,如果它是一个 const 数组。)如果你有一个大数组,它以 mostly-zeroed 开头但有几个 non-zero 元素,你可以保存 space 和 load-time 通过将其写为 all-zero,并带有初始化程序。 (C 没有任何关于全局构造函数的规定,但 C++ 有)。

functions/methods中的数组局部变量(即在堆栈上分配)需要在每次初始化时写入。编译器通常会生成内联内存集(循环或完全展开),甚至是对 memset.

的调用

Local-variable 数组初始化花费线性时间(和缓存污染)。全局/静态数组初始化为全零是免费的(因为内核可以有效地为 BSS 获取零页内存)。具有单个 non-zero 初始值设定项的全局/静态数组在 I/O 中花费线性 process-startup 时间(如果您实际读取整个数组)从磁盘读取数据(即使是零部分) .

标准只要求数组在使用前进行初始化。它还表示,如果未明确初始化,具有静态存储持续时间的对象将被初始化为 0,而如果未明确初始化,具有动态存储持续时间的对象将被初始化为不确定值。

常用规则是:

  • 具有静态存储持续时间的对象在构建时初始化(编译 + link)
  • 具有动态存储持续时间的对象只能在 运行 时间初始化。在您的示例中,它看起来像一个 memset:时间将与全局大小大致成线性关系。

编译器会将第一个数组元素设置为您提供的值 (0),所有其他元素都将设置为零,因为它是省略的数组元素的默认值。

All elements of array the compiler will initialise the elements to 0. How is this done by the compiler?

通过以实现定义的方式将 0s 写入相关内存。