1

我正在将一些 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 时会发生这种情况。

4

6 回答 6

3

这是正确的。

字符串文字是不可变的,并且"---------"是字符串文字。您static char*指向该字符串文字。

不变性并不是在编译时固有地强制执行的,因此当您尝试写入文字时,您会得到未定义的行为。这可能会导致运行时崩溃。

[C++11: 2.14.5/12]:是否所有字符串文字都是不同的(即,存储在不重叠的对象中)是实现定义的。尝试修改字符串文字的效果是未定义的。

C++ 实际上要求这个指针是 a static char const*,尽管一些编译器只对此发出警告

但是,使用字符串文字初始化数组将复制字符串。数组是你自己的,你可以随意使用。这就是为什么您可以在static char[10]不崩溃的情况下进行修改。

[C++11: 8.5.2/1]:char 数组(无论是普通charsigned char还是unsigned char)、char16_t数组、char32_t数组或wchar_t数组可以分别由窄字符文字、char16_t字符串文字、char32_t字符串文字或宽字符串文字初始化,或者用括号括起来的适当类型的字符串文字初始化. 字符串文字值的连续字符初始化数组的元素。

于 2013-07-02T12:17:37.620 回答
2

字符串文字是const char *. 您不能在 C++ 或 C 中修改它们。

由于遗留原因,它们可以转换为char *,但这并不意味着修改它们是合法的。

于 2013-07-02T12:18:15.860 回答
2

当您编写以下内容时:

const char *X = "...."

"...."在只读内存中并X指向它。事实上,type ofX应该是const char *,而不仅仅是char *

另一方面,当你写:

char X[] = "...."

这相当于:

char X[] = {'.', '.', '.', '.', '\0'}

这是一个数组初始值设定项。换句话说,X它将是一个数组(不是指针),它将包含"....". 既然不是const,您可以毫无问题地更改它。

于 2013-07-02T12:17:43.523 回答
1

字符串文字存储在内存的只读部分中。任何修改字符串文字内容的尝试都会在大多数实现中调用未定义行为和分段错误。所以如果你需要一个可修改的 char 数组,那么将它声明为char perms[10]而不是char* perms

于 2013-07-02T12:17:33.197 回答
0

这是正常的,与 c++ 无关(你将与 C 有相同的结果)。static char* perms = "---------";是 const 因为"---------"它是你的二进制文件的一部分(你可以用objdumpprogramm 看到它)

于 2013-07-02T12:18:26.310 回答
0

char* perms = "-----"创建一个指向字符串的指针,该字符串位于受保护的段中。试图写入它会导致崩溃。

char perms[] = "-----"在堆栈上创建一个字符数组,并用“-----”中的相关字符填充它。

这是一个数组和指针不等价的例子。

于 2013-07-02T12:19:10.060 回答