声明一个static
数组(基元类型)和一个static const
数组(基元类型)在内存使用方面有区别吗?
static const int array[4] = {1,2,3,4};
// vs
static int array[4] = {1,2,3,4};
具体地说,static const
数组是否“简单地”是加载到内存中的可执行文件的数据,而在只有static
的情况下是该数组的副本?后者则意味着数据在内存中存在两次,需要在启动期间复制。
我特别考虑的是一个对单元全局的数组(在cpp文件中声明)。在内存方面,在函数内部声明有什么区别吗?(如果复制了)是在函数被第一次调用时复制的吗?那么,如果该函数从未被调用呢?
PS.我目前使用C++ Builder 11.3使用Clang
1条答案
按热度按时间33qvvth11#
首先,请注意,这取决于很多事情-系统类型和使用的编译器,启用的优化级别,“C运行时”如何为给定系统工作等等。
与常见的误解相反,数据不能存储在“稀薄的空气”中-它总是要去某个地方。编译器可以做的是优化数组分配,并将数组内容放在机器码中。数据部分缩小,但可执行部分增加-分配的内存总量应该大致相同。
这种优化的原因通常是速度优化-如果您不必将值从RAM加载到寄存器中,则可以减少指令的总量。
例如
在x86_64的gcc -O3上,这归结为一堆
movl $1, %esi
,movl $2, %esi
等指令。数字仍然存在,但可执行代码中的movl
指令的一部分。一些注意事项:
static
,无论我们是否使用const
,都会发生上述优化。static
但保留const
,那么程序的其他部分可能会访问数组但不会更改它,因此同样的优化仍然是可能的。static
和const
,那么编译器就不能再假设这个数组没有从其他地方修改过。因此,编译器被迫将其分配为数据部分中的数组,并在打印期间从该内存位置读取它。具体地说,静态常量数组是否“仅仅”是加载到内存中的可执行文件的数据,而仅仅是静态数组的副本?
假设数组实际上是在数据段中分配的,并且没有优化为机器码,那么:
static
+const
的情况下,阵列存储在真正的只读闪存中,任何地方都没有副本。static
和/或声明在文件作用域但没有const
,则数组存储在RAM中,其初始化器值必须在只读闪存中分配。在程序启动期间,闪存数据被复制到RAM中的阵列中。在某种程度上,各种托管系统编译器的“C运行时”(CRT)可能会做类似于上述独立场景的事情-保留初始化器值的副本,这些初始化器值在启动期间上传到数组中。例如,在C++类的情况下,可能有默认的构造函数,它们执行比复制值更复杂的操作。
在内存方面,在函数内部声明有什么区别吗?
这完全是另一个故事。
static
的局部作用域变量在分配/初始化方面与任何其他static
变量的工作方式相同。但是普通的局部作用域变量“自动存储”存储在寄存器或堆栈中,每次进入声明它们的作用域时,它们都会重新设置。因此,这些将需要从其他地方的只读存储器中复制默认的初始化值。在这里,局部变量是否是
const
并不重要,它仍然会在堆栈上的寄存器/中分配,并从只读内存中初始化。