字符串初始化程序和只读部分
假设我有一个数组(函数的本地)和一个指针
char a[]="aesdf"
和char *b="asdf"
我的问题是,在前一种情况下,字符串文字"aesdf"
是存储在只读部分中,然后复制到本地数组还是类似于
char a[]={'a','e','s','d','f','\0'};
?
我认为在这种情况下,字符直接在堆栈上创建,但在前面的情况下( char a[]="aesdf"
),字符从只读部分复制到本地数组。
在可执行文件的整个生命周期中是否存在“aesdf”?
从抽象和forms的角度来看,每个字符串文字都是一个具有静态存储持续时间的独立无名对象。 这意味着,初始化char a[] = "aesdf"
正式创建文字对象"aesdf"
然后用它来初始化独立数组a
,即它不等于char *a = "aesdf"
,其中指针是直接指向字符串文字。
但是,由于字符串文字是无名对象,因此在char a[] = "aesdf"
变体中,无法在初始化之前或之后访问独立的"aesdf"
对象。 这意味着您无法“检测”此对象是否确实存在。 该对象的存在(或不存在)不会影响程序的可观察行为。 由于这个原因,实现可以自由地消除独立的"aesdf"
对象,并以任何其他方式初始化数组,从而产生预期的正确结果,即char a[] = { 'a', 'e', 's', 'd', 'f', '\0' }
或作为char a[] = { 'a', 'e', "sdf" }
或其他内容。
第一:
char a[]="aesdf";
假设这是一个自动局部变量,它将在堆栈上分配6个字节并使用给定的字符初始化它们。 它是如何做到的(无论是通过字符串文字中的memcpy还是一次使用内联存储指令加载一个字节,或者其他方式)都是完全实现定义的。 请注意,每次变量进入范围时都必须进行初始化,因此如果它不会改变,那么这是一个非常浪费的构造。
如果这是一个静态/全局变量,它将产生一个6字节的字符串数组,其中包含唯一的地址/存储,其初始内容是给定的字符,并且是可写的。
下一个:
char *b="asdf";
这会将指针b
初始化为指向字符串文字"asdf"
,它可能会或可能不会与其他字符串文字共享存储,并且如果您写入它则会产生未定义的行为。
a [] =“aesdf”和char a [] = {‘a’,’e’,’s’,’d’,’f’,’\ 0’}都将存储在函数的运行时堆栈和内存中将在函数返回时释放。 但是对于char * b =“asdf”,asdf存储在readonly节中并从那里引用。
char a[] = "aesdf"; char a[] = {'a','e','s','d','f','\0'};
这两行代码具有相同的效果。 编译器可以选择以相同的方式实现它们,或者它可以选择以不同的方式实现它们。
从程序员用C编写代码的角度来看,这应该不重要。 您可以使用其中任何一个,并确保最终将初始化为指定内容的六元素char
数组。
在可执行文件的整个生命周期中是否存在
"aesdf"
?
从语义上讲,是的。 字符串文字是具有静态存储持续时间的字符串数组。 具有静态存储持续时间的对象具有执行程序的生命周期:它在程序启动之前初始化,并且一直存在直到程序终止。
但是,这在您的程序中根本不重要。 该字符串文字用于初始化数组a
。 由于您没有获得指向字符串文字本身的指针,因此该字符串文字的实际生命周期或实际存储方式无关紧要。 只要数组a
被正确初始化,编译器就可以做任何它认为合适的事情。