如果我想存储一个常量字符串,
const char array[] = "Some string literal.";
Run Code Online (Sandbox Code Playgroud)
C引子加书说
然后,引用的字符串存储在作为可执行文件一部分的数据段中.只有在程序开始运行后才会分配数组的内存.那时,引用的字符串被复制到数组中.
这是否意味着内存为字符串文字分配了两次?
另一方面,当使用指针声明时,它仅为指针变量留出存储空间并将字符串文字的地址存储到其中.
const char *pt = "Some string literal.";
Run Code Online (Sandbox Code Playgroud)
这意味着只有一个字符串文字的副本,并且使用字符串文字声明指针比数组的内存效率更高?
在第一种情况下,字符串的数据存储在可执行文件中,并在加载程序后存储在内存中.所以它是"分配两次",但是在非常不同的存储介质(磁盘和内存)中.
然而,对于第二种情况也是如此.字符串文字需要在磁盘上的可执行文件中存储一次,在程序运行时存储在内存中.
不同之处在于实现细节,即在第一种情况下,存储器中的字符串存储在堆栈上或存储在某个全局可修改数据存储器段中.在第二种情况下,字符串通常与代码一起存储.
因此,如果在第一种情况下只有一个字符串实例,则"内存效率"没有区别.
答案取决于定义是出现在全球范围还是局部范围内.
在全球范围内:
第一个选项定义初始化常量数组.从中读取字节array[0]将导致代码从全局内存位置读取单个字节,通常是单个指令.
第二个选项定义了一个可修改的指针,该指针被初始化为指向一个常量字符数组.从中读取字节array[0]将导致代码加载指针值并读取指针指向的元素,通常至少有2条指令.
如果您不需要更改字符串array引用,则最好使用第一个选项.
在本地范围(自动存储)
第一个选项定义用字符串初始化的数组.如果此数组不是常量并且在函数内部被修改,则生成的代码将与此基本类似:
char array[sizeof "Some string literal."];
memcpy(array, "Some string literal.", sizeof(array));
Run Code Online (Sandbox Code Playgroud)
但由于它被定义为const,编译可以优化代码并生成对array静态存储中字符串文字的引用的引用.为避免可能的代码生成(如上所述),您可以在本地范围内使用此定义:
static const char array[] = "Some string literal.";
Run Code Online (Sandbox Code Playgroud)相反,第二个选项定义了一个初始化为指向字符串文字的本地指针,它本身很可能存储在静态存储器中,例如数据段甚至代码段.如果函数使用array,定义可以生成一个存储来初始化指针,或多或少的代码从中读取字符,具体取决于函数内部的特定代码和编译器的效率.
在全球范围内,使用第一种方法似乎更有效.
在本地范围,它很大程度上取决于实际使用的代码和编译器,但定义static const char数组可能是最有效的.