我总是尽量避免返回字符串文字,因为我担心它们没有在函数外部定义。但我不确定是否是这种情况。例如,我们来看看这个功能:(字符串)文字的范围
const char *
return_a_string(void)
{
return "blah";
}
这是正确的代码吗?它对我有用,但也许它只适用于我的编译器(gcc)。所以问题是,do(字符串)文字是否有范围,或者它们是否始终存在/定义。
我总是尽量避免返回字符串文字,因为我担心它们没有在函数外部定义。但我不确定是否是这种情况。例如,我们来看看这个功能:(字符串)文字的范围
const char *
return_a_string(void)
{
return "blah";
}
这是正确的代码吗?它对我有用,但也许它只适用于我的编译器(gcc)。所以问题是,do(字符串)文字是否有范围,或者它们是否始终存在/定义。
这段代码在所有平台上都很好。该字符串被编译为二进制文件作为静态字符串文字。如果你在windows上,你甚至可以用记事本打开你的.exe文件,然后搜索字符串本身。
由于它是一个静态字符串,字面范围并不重要。
字符串池:
一件事看出来的是,在某些情况下,相同的字符串文字可以被“合并”,以节省空间的可执行文件。在这种情况下,每个相同的字符串文字可能具有相同的内存地址。你永远不应该认为它会或不会是这样。
在大多数编译器中,您可以设置是否将静态字符串池用于stirng文字。
字符串文字的最大尺寸:
一些编译器对字符串文字的最大尺寸。例如对于VC++,这大约是2048字节。
修改字符串字面给人未定义行为:
修改字符串文字不应该做。它有一个未定义的行为。
char * sz = "this is a test";
sz[0] = 'T'; //<--- undefined results
宽字符串文字:
所有的上述同样适用于宽字符串文字。
例如:L“这是一个宽字符串”;
C++标准状态:(部分lex.string)
1字符串文字是由双引号所包围的字符序列 (如在 lex.ccon定义),任选从 字母L开始,如“...”或L“...”中所示。不与L一起开始 的字符串文字是普通的字符串文字,也被称为窄字符串文字。普通字符串文字具有类型和静态存储持续时间(basic.stc),其中n是如下面所定义,并且与给定的字符 初始化字符串的大小 “N 常量 char数组”。以L开头的字符串文字,例如L“asdf”, 是宽字符串文字的 。宽字符串文字的类型为“数组 n const wchar_t”并且具有静态存储持续时间,其中n是大小为 的 字符串(如下定义),并使用给定的字符串进行初始化。
2是否所有字符串文字都是不同的(即,存储在 不重叠的对象中)是实现定义的。尝试修改字符串文字的效果 的 未定义。
是的,没关系。他们住在一个全局的字符串表中。
不,字符串文字没有范围,所以您的代码可以保证在所有平台和编译器中都可以工作。它们存储在程序的二进制图像中,因此您可以随时访问它们。但是,试图写信给他们(通过丢弃const
)将导致未定义的行为。
实际上,您会返回一个指向存储在可执行文件的数据部分中的零终止字符串的指针,该区域在加载程序时加载。只要避免尝试和改变字符,它可能会给出不可预知的结果...
注意到Brian提到的未定义结果是非常重要的。既然你已经声明函数返回一个const char *类型,你应该没问题,但是在许多平台上,字符串文字被放到可执行文件(通常是文本段)的只读段中,并修改它们会导致访问冲突在大多数平台上。
正如其他人所解释的,这在C(或C++)中是有效的。
我能想到的一件事就是如果你使用dll,那么如果包含这段代码的dll被卸载,指针将不会保持有效。 C(或C++)标准并不理解或考虑在运行时加载和卸载代码,因此任何做这些都会面临实现定义的后果:在这种情况下,结果是字符串文字应该具有静态存储持续时间,从调用代码的POV中出现不会持续整个程序的持续时间。
我给你举个例子,这样你的困惑变得有些清晰
char *f()
{
char a[]="SUMIT";
return a;
}
这不会工作。
但
char *f()
{
char *a="SUMIT";
return a;
}
这个工程。
原因:“SUMIT”是一个具有全局范围的文字。而数组只是字符序列{'S','U','M','I','T''\ 0'} 的范围有限,并且只要程序是返回。
希望这有助于
既然你明确提到宽字符串文字,每做文字表现呀?随着每一次我指的是C99复合文字。 – quinmars 2008-11-05 23:56:26