请参阅以下声明:
char a[5]="jgkl"; // let's call this Statement A
char *b="jhdfjnfnsfnnkjdf"; // let's call this Statement B , and yes i know this is not an Array
char c[5]={'j','g','k','l','\0'}; // let's call this Statement C
现在,陈述A和C之间有什么区别吗? 我的意思是两个都应该在Stack上吗?只有b将位于静态位置。
所以不会让“jgkl”存在于程序的整个生命周期的静态位置吗?既然它应该是只读/常数? 请澄清。
答案 0 :(得分:5)
不,因为语句A中的字符“jgkl”用于初始化a
,它不会在可执行文件中为字符串创建存储(除了您创建的存储之外)通过声明a
)。此声明在读写内存中创建一个包含字节{'j','g','k','l','\0'}
的字符数组,但用于初始化它的字符串在可执行结果中不存在。
在语句B中,字符串文字的地址用作初始化程序。变量char *b
是存储在读写存储器中的指针。它指向字符串"jhdfjnfnsfnnkjdf"
。此字符串存在于可执行映像中通常称为“.sdata”的段中,表示“静态数据”。该字符串通常存储在只读存储器中,如C标准所允许的那样。
这是声明一个字符数组和一个字符串常量之间的一个关键区别:即使你有一个指向字符串常量的指针,你也不应该修改内容。
在初始化时,根据ANSI C标准第6.5.7节,尝试修改字符串常量是“未定义的行为”。
答案 1 :(得分:2)
如果[]是静态的那么c [] - 两者是等价的,也不是字符串文字。这两个同样可以被声明,以便它们在堆栈中 - 它取决于它们的声明位置和方式,而不是用于指定其内容的语法。
答案 2 :(得分:2)
值“jgkl”可能永远不会加载到工作内存中。在调用main
之前,运行一个函数(通常称为cinit
)。此函数执行的操作之一是初始化静态和文件范围变量。在我使用的DSP编译器上,初始值存储在一个表中,该表是程序映像的一部分。表格的格式与正在初始化的变量的格式无关。初始化程序表仍然是程序映像的一部分,永远不会复制到RAM。简单地说,内存中无处可以访问“jgkl”。
像a
这样的小字符串可能根本不存储在该表中。优化器可以将其减少到等效(伪指令)store reg const(152<<24|167<<16|153<<8|154)
我怀疑大多数编译器是相似的。
答案 3 :(得分:1)
A和C完全相同。 A中使用的语法是C语法的缩写。
名为a
和c
的每个对象都是长度为5的字节数组,存储在内存中的某个位置,该位置在执行期间是固定的。程序可以随时更改元素字节。编译器负责决定如何初始化对象。编译器可能生成类似于a[0] = 'j'; a[1] = 'g'; ...
的东西,或类似于memcpy(a, static_read_only_initialization_data[1729], 5)
的东西,或者它选择的任何东西。如果声明发生在函数中,则数组位于(概念)堆栈上;如果声明发生在文件范围内,则数组位于全局可写内存中。
名为b
的对象是指向字节的指针。它的初始值是一个指向字符串文字内存的指针,它在许多具有只读内存的实现上是只读的,但不是全部。 b
的值可能会更改(例如,指向不同的字符串,或指向NULL
)。该程序不允许更改jhdfjnfnsfnnkjdf"
的内容,尽管通常在C中实现可能不会强制执行此操作。
答案 4 :(得分:0)
C-Literals始终是只读的。