在理查德·里斯(Richard Reese)所著的《Understanding and Using C Pointers》一书中,作者在第110页指出

"可以使用初始化操作符初始化chararray.在下面的示例中,头数组初始化为字符串字面量中包含的字符:

char header[] = "Media Player";

后来它指出:

"...假设声明位于主函数中,初始化将这些字符复制到以NUL字符结束的数组中,如图5-2所示.

在第111页的图5-2(初始化char数组)中,它显示了位于堆栈上的头数组及其内存地址,但它还显示了用于初始化位于字符串Literal Pool中不同内存地址的数组的字符串.

我发现这与我在KN的书中读到的内容不一致King C Programming A Modern Approach第2版.其中在第281页上,数组初始化如下

char date1[8] = "June 14";

后来在第282页上写道:

尽管"June 14"看起来是字符串字面意思,但事实并非如此.相反,C将其视为数组初始化器的缩写.

根据后面的文本,以及我有限的理解,我认为文本Understanding and Using C Pointers在用于初始化数组时声明"Media Player"是字符串字面量是错误的--它似乎并不是简单地使用术语"字符串字面量"作为字符串的同义词,因为文本随后错误地(?)显示"媒体播放器"位于字符串文本池中,并具有自己的内存地址.

我的理解正确吗?

推荐答案

我们可以在两个层面上考虑C程序的作用.C标准使用抽象机器的模型指定C程序的语义.当C实现翻译和执行程序时,它可以以任何产生相同observable behavior的方式实现该程序,这就是程序访问易失性对象、将数据写入文件以及与输入/输出设备交互的方式.这允许编译器优化程序.

在抽象级别,根据C 2018 6.4.5 6,每个字符串字面量都会导致创建一个包含字符串字面量字符的数组:

在翻译阶段7,值为零的字节或代码被附加到由字符串字面量或字面量产生的每个多字节字符序列.然后使用多字节字符序列来初始化一个静态存储持续时间和长度刚好足以包含该序列的array.

创建和初始化的这个数组与程序也可能初始化的命名数组不同.例如,在char header[] = "Media Player";中,存在一个包含"Media Player"字符和空字符的未命名数组,并且存在通过将未命名数组复制到已命名数组来初始化的已命名数组header.

在实际的C实现中,编译器通常会根据上下文以各种方式优化数组初始化:

  • 对于静态存储持续时间数组,例如在任何函数外部定义的数组或在函数内部定义的数组,编译器可以在对象模块内创建以其中的数据开始的空间.也就是说,对象文件包含一个或多个部分,这些部分有效地表示"当程序启动时,为此部分分配内存并使用对象模块中的字节初始化它."一旦操作系统实际向程序提供了数组的内存,它就会用数据初始化.从程序的Angular 来看,即使使用调试器进行内部查看,命名数组也会立即出现,其中包含初始数据;字符串文本没有单独的array.1
  • 对于无法以其他方式优化的自动存储持续时间数组,编译器确实需要保留由字符串字面量创建的单独array.然后,每次需要数组时(例如,调用其定义的函数),编译器都会将数据从字符串字面量数组复制到命名数组的内存中(通常是硬件堆栈上的空间).使用调试器,我们可以看到数据从字符串字面量数组复制到该数组使用的堆栈空间中.
  • 如果数组很短,编译器可能会将其初始数据构建到程序指令中.许多处理器体系 struct 提供包含少量"立即数据"的指令,这些数据可用于构建小常数和短字节序列.
  • 在可能进行进一步优化的情况下,例如,编译器可以检测到该 routine 仅被调用一次,或者数组定义为const并且其地址没有传递到该 routine 之外,编译器可能能够将其类似于静态数组来处理.

脚注

1我们几乎可以认为这与抽象语义相同:对象模块包含为字符串字面量创建的数组,内存中的数组用它初始化.因此,确实有两个数组,对象模块中的一个未命名数组和内存中的一个已命名array.然而,在抽象模型中,为字符串字面量创建的数组位于抽象计算机的内存中.假设它会有一个地址(尽管我们从未访问过它的地址).对象模块中的数据以这种方式不在程序的内存中,因此它实际上与抽象语义不相同.

C++相关问答推荐

C/SDL程序,渲染不使用我的渲染器

C中是否有语法可以直接初始化一个常量文本常量数组的 struct 成员?

如何在C中从函数返回指向数组的指针?

为什么在函数内部分配内存空间时需要添加符号?

在C++中头文件中声明外部 struct

拥有3x3二维数组并访问数组[1][3]等同于数组[2][0]?

预先分配虚拟地址空间的区域

如何使用_newindex数组我总是得到错误的参数

C代码在字符串中删除不区分大小写的子字符串的问题

如何用C语言为CLI应用程序编写按键检测系统?

预处理器宏扩展(ISO/IEC 9899:1999(E)§;6.10.3.5示例3)

C语言中的外部关键字

理解bzip2的BZ2_解压缩函数中的状态重新分配

为什么这个分配做得不好呢?

如何在不使用字符串的情况下在c中编写函数atof().h>;

*S=0;正在优化中.可能是GCC 13号虫?或者是一些不明确的行为?

UpDown控制与预期相反

const struct 成员的 typedef 中的灵活数组大小

C/C++编译器可以在编译过程中通过按引用传递来优化按值传递吗?

全局变量 y0 与 mathlib 冲突,无法编译最小的 C 代码