C中文字字符串的内存使用情况

时间:2014-07-31 20:47:48

标签: c string memory compiler-construction string-literals

当您将字符串lteral传递给参数中的函数而不是指向字符数组的指针时,编译器如何管理内存?

示例:

static const char myString[LENGTH] = "A string";
myFunction(myString);

myFunction("A string");

通过指针传递静态const(很可能存储在ROM中)会产生关于RAM使用的显着好处吗?

当传递字符串文字时,它完全复制为sizeof(myString)的局部变量或编译器"知道"通过引用传递它,因为数组总是通过C?

中的引用传递

6 个答案:

答案 0 :(得分:3)

该标准没有规定如何使用字符串文字,或者即使共享或不共享不同部分中使用的相同字符串文字。它只是说它们有静态存储持续时间,修改它们是未定义的行为。否则,字符串文字只是一个字符数组,并相应地表现。

草案C99标准部分6.4.5 字符串文字中涵盖了这一点:

  

在转换阶段7中,将值为零的字节或代码附加到每个多字节   由字符串文字或文字产生的字符序列.66)多字节字符   然后,序列用于初始化静态存储持续时间和长度的数组   足以包含序列。对于字符串文字,数组元素具有   键入char,

  

如果这些数组的元素具有不同的数据,则未指定   适当的价值观如果程序试图修改这样的数组,则行为是   未定义。

在分配给myString的情况下,它将被复制到为myString分配的内存中,这将在6.7.8 初始化部分中介绍: / p>

  

字符串数组可以由字符串文字初始化,可选   用括号括起来。字符串文字的连续字符(包括   如果有空间或数组的大小未知,则终止空字符)初始化   数组的元素。

答案 1 :(得分:3)

  

当传递字符串文字时,它完全复制为sizeof(myString)的局部变量,或者编译器“知道”通过引用传递它,因为数组总是通过C中的引用传递?

字符串文字存储作为一个数组,以便它在程序的生命周期内可用,并且与任何其他数组表达式具有相同的转换规则。也就是说,除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化数组的字符串文字,表达式为“N元素数组{ {1}}“将被转换(”衰减“)到”指向T的指针“类型的表达式,表达式的值将是数组中第一个元素的地址。因此,在电话中

T

myFunction( mystring );

两个参数都是数组类型的表达式,也不是myFunction( "A string" ); 或一元sizeof运算符的操作数,因此在两种情况下,表达式都会衰减为指向第一个元素的指针。就函数调用而言,两者之间绝对没有区别。

让我们看一个真实的例子(SLES 10,x86_64,gcc 4.1.2)

&

#include <stdio.h> void myFunction( const char *str ) { printf( "str = %p\n", (void *) str ); printf( "str = %s\n", str ); } int main( void ) { static const char mystring[] = "A string"; myFunction( mystring ); myFunction( "A string" ); return 0; } 打印出字符串文字和myFunction变量的地址和内容。结果如下:

mystring

字符串文字和[fbgo448@n9dvap997]~/prototypes/literal: gcc -o literal -std=c99 -pedantic -Wall -Werror literal.c [fbgo448@n9dvap997]~/prototypes/literal: ./literal str = 0x400654 str = A string str = 0x40065d str = A string 数组都存储在可执行文件的mystring(只读)部分中:

.rodata

[fbgo448@n9dvap997]~/prototypes/literal: objdump -s literal ... Contents of section .rodata: 40063c 01000200 73747220 3d202570 0a007374 ....str = %p..st 40064c 72203d20 25730a00 41207374 72696e67 r = %s..A string 40065c 00412073 7472696e 6700 .A string. ... 声明中的static关键字告诉编译器mystring的内存应该在程序启动时保留并保持到程序终止。 mystring关键字表示内存不应该由代码修改。在这种情况下,将其粘贴在const部分非常有意义。

这意味着在运行时没有为.rodata分配额外的内存;它已经被分配为图像的一部分。在这种特殊情况下,对于这个特定的平台,使用一个或另一个之间绝对没有区别

如果我mystring声明为mystring,则

static
然后我们得到:

int main( void )
{
  const char mystring[] = "A string";
  ...

意味着只有字符串文字存储在str = 0x7fff2fe49110 str = A string str = 0x400674 str = A string

.rodata

由于它被Contents of section .rodata: 40065c 01000200 73747220 3d202570 0a007374 ....str = %p..st 40066c 72203d20 25730a00 41207374 72696e67 r = %s..A string 40067c 00 . 声明为本地,而未声明为main ,因此static被分配mystring存储持续时间;在这种情况下,这意味着将在运行时从堆栈中分配内存,并将在auto的封闭范围(即mystring函数)的持续时间内保留。作为声明的一部分,字符串文字的内容将被复制到数组中。由于它是从堆栈中分配的,因此数组原则上是可修改的,但main关键字告诉编译器拒绝任何试图修改它的代码。

答案 2 :(得分:2)

最有可能的是内存使用量没有差异。

在这两种情况下,字符串都将存储在某个静态位置,编译器只会使用指向字符串的方式。对你而言,它意味着内存使用完全相同。

如果引用的字符串很少,则第二种情况(文字字符串)可能更有效 - 编译器将只使用一个指针。第一种情况必须分配多个具有完全相同内容的内存位置。

答案 3 :(得分:2)

字符串文字在内存中的存储方式没有区别,无论您是否使用constantstatic 存储类修饰符< / strong>,或者如果您将其用作函数参数而不是中间变量/指针:它们始终存储在代码段中。优化器还将使用文本本身的地址替换对中间指针MY_STRING的引用。

示例如下所示:

Example:                       Allocation Type:   Read/Write:  Storage Location:
============================================================================
const char* str = "Stack";     Static             Read-only    Code segment
char* str = "Stack";           Static             Read-only    Code segment
char* str = malloc(...);       Dynamic            Read-write   Heap
char str[] = "Stack";          Static             Read-write   Stack
char strGlobal[10] = "Global"; Static             Read-write   Data Segment (R/W)

参考文献

  1. 声明字符串与已分配字符串之间的区别,已访问2014-07-31,<https://stackoverflow.com/questions/16021454/difference-between-declared-string-and-allocated-string>

答案 4 :(得分:0)

在C中,数组确实通过引用传递。字符串文字也不例外。

答案 5 :(得分:0)

静态字符串将在RAM中存储一次。字符串文字将在RAM中存储一次。传递给函数时,静态位置将被加载并作为参数传递或传递文字位置。存储没有区别。

但是,将文字字符串保存在一起并引用它们将比通过代码传播字符串文字更具可维护性。