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