我正在将一些C代码编译为C ++,并且遇到了令我困惑的事情。考虑从LuaFileSystem获取的以下函数。
static const char *perm2string (unsigned short mode) {
static char perms[10] = "---------";
//static char* perms = "---------";
int i;
for (i=0;i<9;i++) perms[i]='-';
if (mode & _S_IREAD)
{ perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; }
if (mode & _S_IWRITE)
{ perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; }
if (mode & _S_IEXEC)
{ perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; }
return perms;
}
此代码可以正常工作,但是如果我取消注释注释行,它就会崩溃。我已经使用调试器来解决这个问题,并且似乎在static char* perms
时,字符串被放置在只读内存中,因此第一个循环将导致访问冲突,使用静态数组不会导致此类问题。我很好奇当字符串未被声明为const时为什么会发生这种情况。
答案 0 :(得分:3)
没错。
字符串文字是不可变的,"---------"
是字符串文字。您的static char*
指向该字符串文字。
不可变性在编译时并不是固有的强制执行,所以当你尝试写入文字时,你会得到未定义的行为。这可能会导致运行时崩溃。
[C++11: 2.14.5/12]:
是否所有字符串文字都是不同的(即存储在非重叠对象中)是实现定义的。 尝试修改字符串文字的效果未定义。
C ++实际上要求此指针为static char const*
,但有些编译器仅警告。
但是,使用字符串文字初始化数组将复制字符串。该阵列是您自己的,随心所欲。这就是为什么你可以在没有崩溃的情况下修改static char[10]
。
[C++11: 8.5.2/1]:
一个char数组(无论是普通char
,signed char
还是unsigned char
),char16_t
数组,char32_t
数组还是{ {1}}数组可以分别由窄字符文字wchar_t
字符串文字,char16_t
字符串文字或宽字符串文字初始化,或者由括在括号中的适当类型的字符串文字初始化。 字符串文字值的连续字符初始化数组的元素。
答案 1 :(得分:2)
撰写以下内容时:
const char *X = "...."
您在只读内存中有"...."
,而X
指向它。事实上,X
的类型应该是const char *
,而不仅仅是char *
。
另一方面,当你写:
char X[] = "...."
这相当于:
char X[] = {'.', '.', '.', '.', '\0'}
这是一个数组初始值设定项。换句话说,X
将是一个数组(不是指针),它将包含"...."
的内容。由于它不是const
,您可以毫无问题地进行更改。
答案 2 :(得分:2)
字符串文字是const char *
。您不能在C ++或C中修改它们。
由于遗产原因,他们可以转换为char *
,但这并不能使其合法修改。
答案 3 :(得分:1)
字符串文字存储在内存的只读部分中。任何修改字符串文字内容的尝试都会在大多数实现中调用Undefined Behavior和segmentation fault。
因此,如果您需要一个可修改的char数组,则将其声明为char perms[10]
而不是char* perms
答案 4 :(得分:0)
这是正常的,与c ++无关(你将得到与C相同的结果)。 static char* perms = "---------";
是const,因为"---------"
是二进制文件的一部分(您可以使用objdump
程序看到它)
答案 5 :(得分:0)
char* perms = "-----"
创建一个指向字符串的指针,该字符串位于受保护的段中。试图写入它会导致崩溃。
char perms[] = "-----"
在堆栈上创建一个字符数组,并用“-----”中的相关字符填充它。
这是一个不相等的数组和指针的例子。