C + + 反对将字符串常量转换为“ char *”

我有一个私人 char str[256];

因此我有一个明确的构造函数:

explicit myClass(char *func)
{
strcpy(str,func);
}

我称之为:

myClass obj("example");

当我编译这个文件时,我会得到以下警告:

不推荐从字符串常量转换为‘ char *’

为什么会这样?

313084 次浏览

事实上,字符串常量文字既不是常量 char * ,也不是 char * ,而是 char []。它很奇怪,但是写在 c + + 规范中; 如果你修改它的行为是未定义的,因为编译器可能会把它存储在代码段中。

无论何时遇到下面这样的情况,您都会看到这个错误消息:

char* pointer_to_nonconst = "string literal";

为什么?C 和 C + + 在字符串文字的类型上是不同的。在 C 中类型是 char 的数组,在 C + + 中是 char 的 不变数组。在任何情况下,都不允许更改字符串文字的字符,所以 C + + 中的 const 实际上并不是一种限制,而更多的是一种类型安全。从 const char*char*的转换通常不可能在没有显式强制转换的情况下进行,这是出于安全考虑。但是为了与 C 向后兼容,C + + 语言仍然允许将字符串文字赋给 char*,并提醒您注意此转换不被推荐。

因此,在程序中的某个地方缺少一个或多个 const来保证常数正确。但是您展示给我们的代码不是问题所在,因为它不执行这种不推荐的转换。警告肯定来自其他地方。

警告:

不推荐从字符串常量转换为‘ char *’

是因为你正在做的事情(不在你发布的代码中)像:

void foo(char* str);
foo("hello");

问题是您正在尝试将字符串文字(类型为 const char[])转换为 char*

您可以将 const char[]转换为 const char*,因为数组会衰减为指针,但是您所做的是将一个可变的指针变成一个常量。

这种转换可能是为了 C 兼容性而允许的,并且只是给出了上面提到的警告。

正如 答案2作者: fnieto-Fernando Nieto清楚而正确地描述的那样,给出这个警告是因为在您的代码中的某个地方您正在做(而不是在您发布的代码中)这样的事情:

void foo(char* str);
foo("hello");

然而,如果你想保持你的代码没有警告,那么只需要在你的代码中做出相应的修改:

void foo(char* str);
foo((char *)"hello");

也就是说,只需将 string常量强制转换为 (char *)

我解决这个问题的方法是在代码开头的某处添加这个宏。或者加入 <iostream>,呵呵。

 #define C_TEXT( text ) ((char*)std::string( text ).c_str())

下面举例说明了解决方案,将字符串分配给指向常量 char 数组的 变量指针(字符串是指向常量 char + 长度 info 数组的 不变指针) :

#include <iostream>


void Swap(const char * & left, const char * & right) {
const char *const temp = left;
left = right;
right = temp;
}


int main() {
const char * x = "Hello"; // These works because you are making a variable
const char * y = "World"; // pointer to a constant string
std::cout << "x = " << x << ", y = " << y << '\n';
Swap(x, y);
std::cout << "x = " << x << ", y = " << y << '\n';
}

有三种解决方案:

解决方案1:

const char *x = "foo bar";

解决方案2:

char *x = (char *)"foo bar";

解决方案3:

char* x = (char*) malloc(strlen("foo bar")+1); // +1 for the terminator
strcpy(x,"foo bar");

数组也可以用来代替指针,因为数组已经是一个常量指针。

更新: 有关解决方案3的安全问题,请参阅注释。

我也有同样的问题。我所做的就是添加 const char * 而不是 char * 。问题解决了。正如前面提到的,这是一个兼容的错误。C 将字符串视为字符数组,而 C + + 将它们视为常量字符数组。

不管怎样,我发现这个简单的包装类对于将 C + + 字符串转换成 char *很有帮助:

class StringWrapper {
std::vector<char> vec;
public:
StringWrapper(const std::string &str) : vec(str.begin(), str.end()) {
}


char *getChars() {
return &vec[0];
}
};

也许你可以试试这个:

void foo(const char* str)
{
// Do something
}


foo("Hello")

对我有用

这个问题的一个原因(这个问题比 char* str = "some string"的问题更难检测——其他人已经解释过了)是当您使用 constexpr的时候。

constexpr char* str = "some string";

它的行为似乎与 const char* str相似,所以不会引起警告,因为它发生在 char*之前,而是表现为 char* const str

细节

常量指针,和指向常量的指针。 const char* strchar* const str之间的区别可以解释如下。

  1. const char* str: 将 str 声明为指向常量字符的指针。这意味着这个指针所指向的数据是常量。可以修改指针,但任何修改数据的尝试都会抛出编译错误。
    1. 我们正在修改指针,而不是被指向的数据。
    2. 我们正试图修改指向的数据。
  2. char* const str: 声明 str 是指向 char 的常量指针。这意味着这个点现在是常数,但被指向的数据也不是。指针不能被修改,但是我们可以使用指针修改数据。
    1. 我们正在尝试修改指针变量,它是一个常量。
    2. *str = 'a';: 有效.我们正试图修改指向的数据。在我们的示例中,这不会导致编译错误,但会导致 < em > 运行时错误 ,因为字符串很可能会进入编译后的二进制文件的只读部分。如果我们有动态分配的内存,例如。char* const str = new char[5];.
  3. const char* const str: 将 str 声明为指向常量字符的常量指针。在这种情况下,我们既不能修改指针,也不能修改指向的数据。
    1. 我们正在尝试修改指针变量,它是一个常量。
    2. 我们试图修改这个指针指向的数据,它也是常量。

在我的案例中,问题是我期望 constexpr char* str表现为 const char* str,而不是 char* const str,因为从视觉上看它似乎更接近于前者。

此外,为 constexpr char* str = "some string"生成的警告与 char* str = "some string"略有不同。

  1. constexpr char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *const'的编译器警告
  2. char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'的编译器警告。

小费

可以使用 英语转换器C声明转换为易于理解的英语语句,反之亦然。这是一个只支持 C的工具,因此不会支持 C++独有的东西(比如 Constexpr)。