如何通过编译器在C中初始化(到零)数组?

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

如果我通过做创建一个数组

int array[15] = {0}; 

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

只是出于好奇而退出。

我假设你在谈论全局变量/数组。

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

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

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

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

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

常见规则是:

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

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

PS例如在IBM大型机中如果我没有弄错,函数memset是用两个mashine指令实现的,比如MVI和MVCL,可以内联。 说真的,我不记得了。 如果您感兴趣,则应查看IBM XL C ++编译器生成的目标代码。

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

但是,如果对数组中的某个值有一个非零的初始化程序,那么整个过程必须进入data部分。 (或rodata ,如果它是一个const数组。)如果你有一个大数组开始大多数归零,但有几个非零元素,你可以通过将其写为全零来节省空间和加载时间,初始化。 (C对于全局变量的构造函数没有任何规定,但C ++确实如此)。

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

局部变量数组初始化花费线性时间(和缓存污染)。 全局/静态数组初始化为全零是免费的(因为内核可以有效地获得BSS的归零页面内存)。 具有单个非零初始化程序的全局/静态数组在I / O中花费线性进程启动时间(如果您实际读取整个数组)以从磁盘读取数据(甚至是零部分)。

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

编译器将数组的所有元素初始化为0.如何由编译器完成?

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