32

我总是尽量避免返回字符串文字,因为我担心它们不是在函数之外定义的。但我不确定是否是这种情况。让我们以这个函数为例:


const char *
return_a_string(void)
{
    return "blah";
}

这是正确的代码吗?它对我有用,但也许它只适用于我的编译器(gcc)。所以问题是,(字符串)文字是否有范围,或者它们是否一直存在/定义。

4

7 回答 7

46

此代码适用于所有平台。该字符串作为静态字符串文字编译到二进制文件中。例如,如果您在 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 const char 数组”类型和静态存储持续时间(basic.stc),其中 n 是如下定义的字符串的大小,并使用给定的字符进行初始化。以 L 开头的字符串文字,例如 L"asdf",是一个宽字符串文字。宽字符串文字的类型为“array of n const wchar_t”并具有静态存储持续时间,其中 n 是字符串的大小,定义如下,并使用给定的字符进行初始化。

2 是否所有字符串文字都是不同的(即存储在不重叠的对象中)是实现定义的。尝试修改字符串文字的效果是未定义的。

于 2008-11-05T23:25:33.740 回答
12

我给你一个例子,让你的困惑变得有点清楚

char *f()
{
char a[]="SUMIT";
return a;
}

这行不通。

char *f()
{
char *a="SUMIT";
return a;
}

这行得通。

原因:"SUMIT"是一个具有全局范围的文字。而只是一个字符序列的数组{'S','U','M','I',"T''\0'} 具有有限的范围,一旦程序返回它就会消失。

于 2011-09-07T09:21:05.020 回答
6

正如其他人所解释的,这在 C(或 C++)中是有效的。

我认为要注意的一件事是,如果您使用的是 dll,那么如果卸载了包含此代码的 dll,则指针将不会保持有效。

C(或 C++)标准不理解或不考虑在运行时加载和卸载代码,所以任何这样做都会面临实现定义的后果:在这种情况下,结果是字符串文字,它应该有静态存储持续时间,从调用代码的 POV 开始出现,不会在程序的整个持续时间内持续存在。

于 2008-11-07T14:08:08.560 回答
3

是的,没关系。它们存在于一个全局字符串表中。

于 2008-11-05T23:25:39.120 回答
3

不,字符串文字没有范围,因此保证您的代码可以在所有平台和编译器上工作。它们存储在程序的二进制映像中,因此您可以随时访问它们。但是,尝试写入它们(通过丢弃const)将导致未定义的行为。

于 2008-11-05T23:26:47.747 回答
0

您实际上返回了一个指向存储在可执行文件数据部分中的以零结尾的字符串的指针,该区域在您加载程序时加载。只是避免尝试更改字符,它可能会产生不可预知的结果......

于 2008-11-05T23:28:04.640 回答
0

记下 Brian 提到的未定义结果非常重要。由于您已将函数声明为返回 const char * 类型,您应该没问题,但在许多平台上,字符串文字被放置在可执行文件的只读段(通常是文本段)中,修改它们会导致访问冲突在大多数平台上。

于 2008-11-06T00:40:15.540 回答