C ++弃用了从字符串常量到'char *'的转换


154

我有一堂课 private char str[256];

为此,我有一个显式的构造函数:

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

我称其为:

myClass obj("example");

当我对此进行编译时,会收到以下警告:

从字符串常量到'char *'的弃用转换

为什么会这样呢?


1
您应该使用strncpy(str, func, 255)而不是strcpy(str, func)更安全的副本。然后不要忘记在字符串的末尾添加“ \ 0”,因为strncpy不会添加它。
帕特里斯·贝纳索拉

2
更安全地说:“ strncpy(str,func,sizeof(str)); str [sizeof(str)-1] ='\ 0';”
沃伦·杨

3
我认为上面的代码不会发出您所引用的警告,尽管我相信代码会非常相似。为了获得有意义的答案,您应该发布一个最小的编译示例以产生警告。
09年

3
@Patrice,沃伦:不要使用strncpy,它不是更安全的strcpy版本。使用(或重新实现)strcpy_s。
史蒂夫·杰索普

我遇到了问题,它仅显示了-X86构建的这些问题,而不是正常的solaris或ARM(target)构建的问题,因此我忽略了这一点。仍然找不到修复程序,因为该示例代码也通常不会显示警告。谢谢你们!
mkamthan

Answers:


144

当您遇到以下情况时,这是一条错误消息:

char* pointer_to_nonconst = "string literal";

为什么?嗯,C和C ++在字符串文字的类型上有所不同。在C语言中,类型是char数组,在C ++中,它是char型常量数组。无论如何,都不允许您更改字符串文字的字符,因此C ++中的const并不是真正的限制,而更多的是类型安全性。从A转换const char*char*一般也不是没有可能的明确的转换出于安全原因。但是为了向后兼容C语言,C ++语言仍然允许为a分配字符串文字,char*并向您发出有关此转换已弃用的警告。

因此,在某些地方您缺少constconst正确性的程序中的一个或多个。但是您显示给我们的代码不是问题,因为它不执行这种不建议使用的转换。该警告一定来自其他地方。


17
不幸的是,考虑到对这个问题的看法和投票,OP从未提供能够实际演示该问题的代码。
Shafik Yaghmour

1
您可以通过constMyClass构造函数中删除来重现OP代码的问题,然后可以通过添加后缀来解决该问题const
西奥多·默多克

145

警告:

从字符串常量到'char *'的弃用转换

给出是因为您正在某处(不在发布的代码中)执行以下操作:

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

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

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

出于C兼容性的考虑,这种转换可能是允许的,只是给您警告。


96

作为答案。2 by fnieto-Fernando Nieto清楚正确地描述了发出此警告的原因,因为您正在执行的代码中的某处(而不是您发布的代码中)如下:

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

但是,如果您也想使代码保持无警告状态,则只需对代码进行相应的更改:

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

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


17
或者,使函数:void foo(const char * str)
Caprooja 2014年

3
@Caprooja是的,在这种情况下也可以将参数声明为“指向常量的指针”。但是,通过这种更改,用户无法再使用用户在实现部分可能正在执行的“ str”指针来更改/重新分配存储在地址中的值。因此,您可能需要注意这一点。
sactiw

1
@sactiw是否有任何理由保持void foo(char* str)原样?我想我们不能modity strfoo无论如何,即使参数被写成非const。
kgf3JfUtW

37

有3个解决方案:

解决方案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");

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


7
对于解决方案3,有strdup。与您的代码不同,它将为终止的NUL字符分配空间,并且不会超出分配范围。
Ben Voigt 2014年

2
应避免解决方案2。
Lightness Races in Orbit

实际上,解决方案2可以是:C ++中的char * x = static_cast <char *>(“ foo bar”)。
蔡凯(Cehe CAI)

3
Anil您是否会将评论整合到您的答案中?解决方案3仍然是危险的错误。
Lightness Races in Orbit Race '09 /

@LightnessRacesinOrbit您能提供一个答案吗?我不明白您为什么要说要避免解决方案2和3,并且它们是错误的错误。
Gladclef

4

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


5
我会说它是const char [],因为作为右值,您不能修改它。
fnieto-Fernando Nieto

3

也许您可以尝试以下方法:

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

foo("Hello")

这个对我有用


2

我通过在代码开头的某个位置添加此宏来解决此问题。或将其添加到中<iostream>,呵呵。

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

8
“或在<iostream>中添加它”什么?!
Lightness Races in Orbit

出于某种原因删除了“
嘿”

C_TEXT对于函数调用(foo(C_TEXT("foo"));)来说很好,但是如果将值存储在类似这样的变量中,则会对未定义的行为大声疾呼char *x = C_TEXT("foo");- x(除赋值外)任何使用都是未定义的行为,因为它所指向的内存已被释放。
马丁·邦纳

1

出现此问题的原因(比char* str = "some string"其他人更难以解决的问题-别人已经解释过了)是在使用时constexpr

constexpr char* str = "some string";

似乎它的行为类似于const char* str,因此不会像以前那样发生警告,char*而是表现为char* const str

细节

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

  1. const char* str:声明str为指向const char的指针。这意味着该指针指向的数据是恒定的。可以修改指针,但是任何试图修改数据的尝试都会引发编译错误。
    1. str++ ;有效。我们正在修改指针,而不是指向的数据。
    2. *str = 'a';无效。我们正在尝试修改所指向的数据。
  2. char* const str:声明str为指向char的const指针。这意味着该点现在是恒定的,但是所指向的数据也不是恒定的。指针不能被修改,但是我们可以使用指针来修改数据。
    1. str++ ;无效。我们正在尝试修改指针变量,它是一个常量。
    2. *str = 'a';有效。我们正在尝试修改所指向的数据。在我们的情况下,这不会导致编译错误,但是会导致运行时错误,因为字符串很可能会进入已编译二进制文件的只读部分。如果我们已经动态分配了内存,则该语句很有意义。char* const str = new char[5];
  3. const char* const str:声明str为指向const char的const指针。在这种情况下,我们既不能修改指针,也不能指向数据。
    1. str++ ;无效。我们正在尝试修改指针变量,它是一个常量。
    2. *str = 'a';无效。我们正在尝试修改此指针指向的数据,该数据也是恒定的。

就我而言,问题在于我期望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)C++


0

我也遇到同样的问题。我所做的只是添加const char *而不是char *。问题解决了。正如其他人在上面提到的,这是一个兼容的错误。C将字符串视为char数组,而C ++将其视为const char数组。


0

对于它的价值,我发现这个简单的包装器类有助于将C ++字符串转换为char *

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

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

-1

以下说明解决方案,将字符串分配给char常量数组的变量指针(字符串是char常量数组的常量指针-加上长度信息):

#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';
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.