当从字符串文字初始化 char 数组时会发生什么?
What happens when a char array gets initialized from a string literal?
据我了解,下面的代码是这样工作的:
char* cptr = "Hello World";
"Hello World" 位于程序内存的 .rodata
部分。字符串文字 "Hello World"
return 是指向字符串基地址的指针,或者所谓的 "array" 中第一个元素的地址,因为字符在内存中按顺序排列它将是 'H'。这是我的小图,因为我将字符串文字可视化存储在内存中:
0x4 : 'H'
0x5 : 'e'
0x6 : 'l'
0x6 : 'l'
0x7 : 'o'
0x8 : ' '
0x9 : 'W'
0xa : 'o'
0xb : 'r'
0xc : 'l'
0xd : 'd'
0xe : '[=11=]'
所以上面的声明变成:
char* cptr = 0x4;
现在 cptr 指向字符串文字。我只是在编地址。
0xa1 : 0x4
现在这段代码是如何工作的?
char cString[] = "Hello World";
我假设在之前的情况下 "Hello World"
也降级为 'H' 和 0x4 的地址。
char cString[] = 0x4;
当 =
与 char 数组的初始化一起使用时,我将其视为重载赋值运算符。据我了解,仅在初始化 C 字符串时,它会从给定的基地址开始逐个字符地复制到 C 字符串中,直到它在复制的最后一个字符中遇到 '\0'。它还为所有字符分配足够的内存。因为重载运算符实际上只是函数,所以我假设它的内部实现类似于 strcpy()
.
我希望一位更有经验的 C 程序员确认我对这段代码如何工作的假设。这是我将字符串文字中的字符复制到其中后的 C 字符串的可视化:
0xb4 : 'H'
0xb5 : 'e'
0xb6 : 'l'
0xb6 : 'l'
0xb7 : 'o'
0xb8 : ' '
0xb9 : 'W'
0xba : 'o'
0xbb : 'r'
0xbc : 'l'
0xbd : 'd'
0xbe : '[=16=]'
再一次,地址是任意的,重点是堆栈中的 C 字符串与内存中 .rodata
部分中的字符串文字不同。
我想做什么?我正在尝试使用 char 指针临时保存字符串文字的基地址,并使用相同的 char 指针(字符串文字的基地址)来初始化 C 字符串。
char* cptr = "Hello World";
char cString[] = cptr;
我假设 "Hello World"
的计算结果为其基地址 0x4
。所以这段代码应该是这样的:
char* cptr = 0x4;
char cString[] = 0x4;
我假设它应该与 char cString[] = "Hello World";
没有什么不同,因为 "Hello World" 求出它的基地址,这就是存储在 char 指针中的内容!
但是,gcc 给我一个错误:
error: invalid initializer
char cString[] = cptr;
^
- 为什么不能使用 char 指针作为临时占位符来存储字符串文字的基地址?
- 这段代码是如何工作的?我的假设是否正确?
- 是否在代码中使用字符串字面值 return "array" 字符存储在内存中的基地址?
您对内存布局的理解或多或少是正确的。但是您遇到的问题是 C 中的初始化语义之一。
此处声明中的 =
符号不是赋值运算符。相反,它是为被实例化的变量指定初始值设定项的语法。在一般情况下,T x = y;
与 T x; x = y;
不同。
有一个语言规则,字符数组可以从字符串文字初始化。 (在此上下文中,字符串文字不是 "evaluated to its base address")。 不是 一种语言规则,即数组可以从指向要复制到数组中的元素的指针初始化。
为什么会有这样的规定? "Historical reasons".
I am assuming that as in the previous situation "Hello World"
also degrades to the address of 'H'
and 0x4
.
不是真的:cString[]
在内存中获得一个全新的地址。编译器为其分配了 12 char
s,并用 "Hello World"
字符串文字的内容初始化它们。
I assume that "Hello World"
evaluates to its base address, 0x4
. Does using a string literal in the code return the base address to the "array" where the chars are stored in the memory?
cString
稍后可能会 转换 为 char*
,产生其基地址,但它在常规上下文中仍然是一个数组。特别是,如果您调用 sizeof(cString)
,您将获得数组的大小,而不是指针的大小。
How come you can't use a char pointer as a temporary placeholder to store the base address of a string literal?
可以。但是,一旦将字符串文字分配给 char *
,它就不再是字符串文字,至少就编译器而言是这样。它变成了一个 char *
指针,与其他 char *
指针没有区别。
请注意,现代 C 编译器将相同的字符串文字组合为优化,因此如果您编写
#define HELLO_WORLD "Hello World"
...
char* cptr = HELLO_WORLD;
char cString[] = HELLO_WORLD;
并打开优化,编译器将消除字符串文字的重复副本。
第二个定义 char cString[] = "Hello World";
是此等效定义的 shorthand:
char cString[12] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '[=10=]' };
如果此定义出现在全局范围内或使用 static
存储,cString
将位于 .data
段中,具有可执行映像中的初始内容。如果它出现在具有自动存储的函数范围之外,编译器将为数组分配自动存储(在堆栈帧或等效项上保留 space)并生成代码以在 运行- 处执行初始化时间.
据我了解,下面的代码是这样工作的:
char* cptr = "Hello World";
"Hello World" 位于程序内存的 .rodata
部分。字符串文字 "Hello World"
return 是指向字符串基地址的指针,或者所谓的 "array" 中第一个元素的地址,因为字符在内存中按顺序排列它将是 'H'。这是我的小图,因为我将字符串文字可视化存储在内存中:
0x4 : 'H'
0x5 : 'e'
0x6 : 'l'
0x6 : 'l'
0x7 : 'o'
0x8 : ' '
0x9 : 'W'
0xa : 'o'
0xb : 'r'
0xc : 'l'
0xd : 'd'
0xe : '[=11=]'
所以上面的声明变成:
char* cptr = 0x4;
现在 cptr 指向字符串文字。我只是在编地址。
0xa1 : 0x4
现在这段代码是如何工作的?
char cString[] = "Hello World";
我假设在之前的情况下 "Hello World"
也降级为 'H' 和 0x4 的地址。
char cString[] = 0x4;
当 =
与 char 数组的初始化一起使用时,我将其视为重载赋值运算符。据我了解,仅在初始化 C 字符串时,它会从给定的基地址开始逐个字符地复制到 C 字符串中,直到它在复制的最后一个字符中遇到 '\0'。它还为所有字符分配足够的内存。因为重载运算符实际上只是函数,所以我假设它的内部实现类似于 strcpy()
.
我希望一位更有经验的 C 程序员确认我对这段代码如何工作的假设。这是我将字符串文字中的字符复制到其中后的 C 字符串的可视化:
0xb4 : 'H'
0xb5 : 'e'
0xb6 : 'l'
0xb6 : 'l'
0xb7 : 'o'
0xb8 : ' '
0xb9 : 'W'
0xba : 'o'
0xbb : 'r'
0xbc : 'l'
0xbd : 'd'
0xbe : '[=16=]'
再一次,地址是任意的,重点是堆栈中的 C 字符串与内存中 .rodata
部分中的字符串文字不同。
我想做什么?我正在尝试使用 char 指针临时保存字符串文字的基地址,并使用相同的 char 指针(字符串文字的基地址)来初始化 C 字符串。
char* cptr = "Hello World";
char cString[] = cptr;
我假设 "Hello World"
的计算结果为其基地址 0x4
。所以这段代码应该是这样的:
char* cptr = 0x4;
char cString[] = 0x4;
我假设它应该与 char cString[] = "Hello World";
没有什么不同,因为 "Hello World" 求出它的基地址,这就是存储在 char 指针中的内容!
但是,gcc 给我一个错误:
error: invalid initializer
char cString[] = cptr;
^
- 为什么不能使用 char 指针作为临时占位符来存储字符串文字的基地址?
- 这段代码是如何工作的?我的假设是否正确?
- 是否在代码中使用字符串字面值 return "array" 字符存储在内存中的基地址?
您对内存布局的理解或多或少是正确的。但是您遇到的问题是 C 中的初始化语义之一。
此处声明中的 =
符号不是赋值运算符。相反,它是为被实例化的变量指定初始值设定项的语法。在一般情况下,T x = y;
与 T x; x = y;
不同。
有一个语言规则,字符数组可以从字符串文字初始化。 (在此上下文中,字符串文字不是 "evaluated to its base address")。 不是 一种语言规则,即数组可以从指向要复制到数组中的元素的指针初始化。
为什么会有这样的规定? "Historical reasons".
I am assuming that as in the previous situation
"Hello World"
also degrades to the address of'H'
and0x4
.
不是真的:cString[]
在内存中获得一个全新的地址。编译器为其分配了 12 char
s,并用 "Hello World"
字符串文字的内容初始化它们。
I assume that
"Hello World"
evaluates to its base address,0x4
. Does using a string literal in the code return the base address to the "array" where the chars are stored in the memory?
cString
稍后可能会 转换 为 char*
,产生其基地址,但它在常规上下文中仍然是一个数组。特别是,如果您调用 sizeof(cString)
,您将获得数组的大小,而不是指针的大小。
How come you can't use a char pointer as a temporary placeholder to store the base address of a string literal?
可以。但是,一旦将字符串文字分配给 char *
,它就不再是字符串文字,至少就编译器而言是这样。它变成了一个 char *
指针,与其他 char *
指针没有区别。
请注意,现代 C 编译器将相同的字符串文字组合为优化,因此如果您编写
#define HELLO_WORLD "Hello World"
...
char* cptr = HELLO_WORLD;
char cString[] = HELLO_WORLD;
并打开优化,编译器将消除字符串文字的重复副本。
第二个定义 char cString[] = "Hello World";
是此等效定义的 shorthand:
char cString[12] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '[=10=]' };
如果此定义出现在全局范围内或使用 static
存储,cString
将位于 .data
段中,具有可执行映像中的初始内容。如果它出现在具有自动存储的函数范围之外,编译器将为数组分配自动存储(在堆栈帧或等效项上保留 space)并生成代码以在 运行- 处执行初始化时间.