C++ 不推荐将字符串常量转换为 'char*'

Posted

技术标签:

【中文标题】C++ 不推荐将字符串常量转换为 \'char*\'【英文标题】:C++ deprecated conversion from string constant to 'char*'C++ 不推荐将字符串常量转换为 'char*' 【发布时间】:2010-12-04 04:57:03 【问题描述】:

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

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

explicit myClass(const char *func)

    strcpy(str,func);

我称之为:

myClass obj("example");

当我编译这个时,我收到以下警告:

不推荐将字符串常量转换为 'char*'

为什么会这样?

【问题讨论】:

您应该使用strncpy(str, func, 255) 而不是strcpy(str, func) 以获得更安全的副本。然后不要忘记在字符串末尾添加 '\0',因为 strncpy 不会添加它。 更安全的说法是 "strncpy(str, func, sizeof(str)); str[sizeof(str) - 1] = '\0';" 我不认为上面给出了你引用的警告,尽管我确信非常相似的代码会。为了获得有意义的答案,您应该发布一个产生警告的最小编译示例。 @Patrice, Warren:不要使用 strncpy,它不是更安全的 strcpy 版本。使用(或重新实现)strcpy_s。 我遇到了问题,它只显示了 -X86 构建的这些问题,而不是普通的 solaris 或 ARM(target) 构建,所以我忽略了这一点。仍然找不到修复程序,因为它也不会正常显示我的示例代码的警告。谢谢大家! 【参考方案1】:

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

【讨论】:

我会说它是 const char[] 因为作为右值你不能修改它。【参考方案2】:

这是您在遇到以下情况时看到的错误消息:

char* pointer_to_nonconst = "string literal";

为什么?好吧,C 和 C++ 在字符串文字的类型上有所不同。在 C 中,类型是 char 数组,而在 C++ 中,它是 constant char 数组。在任何情况下,您都不允许更改字符串文字的字符,因此 C++ 中的 const 并不是真正的限制,而是更多的类型安全。从const char*char* 的转换通常在没有显式转换的情况下出于安全原因是不可能的。但为了与 C 向后兼容,C++ 语言仍然允许将字符串文字分配给 char*,并警告您不推荐使用此转换。

因此,为了 const 的正确性,您的程序中缺少一个或多个 consts。但是您向我们展示的代码不是问题,因为它没有进行这种已弃用的转换。警告一定来自其他地方。

【讨论】:

不幸的是,考虑到对这个问题的看法和投票,OP 从未提供实际证明问题的代码。 您可以通过从MyClass 构造函数中删除const 来重现OP 代码的问题...然后您可以通过添加const 来修复它。【参考方案3】:

警告:

不推荐将字符串常量转换为 'char*'

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

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

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

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

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

【讨论】:

【参考方案4】:

正如answer no. 2 by fnieto - Fernando Nieto 清楚且正确地描述,给出此警告是因为您在代码中的某处(而不是在您发布的代码中)执行以下操作:

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

但是,如果您想让您的代码也没有警告,那么只需对您的代码进行相应的更改:

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

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

【讨论】:

或者,制作函数:void foo(const char* str) @Caprooja 是的,在这种情况下也可以将参数声明为“指向常量的指针”。但是通过这种更改,用户不能再使用用户可能在实现部分中执行的“str”指针更改/重新分配存储在地址中的值。因此,您可能需要注意这一点。 @sactiw 有什么理由让void foo(char* str) 保持原样吗?我以为我们无论如何都不能在foo中修改str,即使参数写成非常量。【参考方案5】:

我通过在代码开头的某个地方添加这个宏来解决这个问题。或者添加到<iostream>,呵呵。

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

【讨论】:

"或者添加到"什么?! 有“,呵呵”,不知为何被删掉了(暗示这是个玩笑) C_TEXT 适用于函数调用 (foo(C_TEXT("foo"));),但如果值存储在 char *x = C_TEXT("foo"); 之类的变量中,则会出现未定义的行为 - 任何使用 x (除了赋值)是未定义的行为,因为它指向的内存已被释放。 良好且可编译并不意味着它实际上可以按预期工作!这将创建一个指向已分配、然后释放并最终在函数中使用的临时成员的指针。这是一个典型的 use-after-free 错误。【参考方案6】:

以下说明了解决方案,将您的字符串分配给一个 variable 指向 char 常量数组的指针(字符串是一个 constant 指向 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';

【讨论】:

【参考方案7】:

有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");

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

【讨论】:

对于解决方案 3,有 strdup。与您的代码不同,它将为终止 NUL 字符分配空间,并且不会超出分配。 避免使用解决方案 2。 其实方案二可以是:char *x = static_cast("foo bar") in C++。 Anil 您是否会将 cmets 集成到您的答案中?解决方案 3 仍然非常错误。 @LightnessRacesinOrbit 你能提供一个答案吗?我不明白你为什么说解决方案 2 和 3 是要避免的,而且是危险的错误。【参考方案8】:

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

【讨论】:

【参考方案9】:

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

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

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

【讨论】:

【参考方案10】:

也许你可以试试这个:

void foo(const char* str) 

    // Do something


foo("Hello")

对我有用

【讨论】:

【参考方案11】:

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

constexpr char* str = "some string";

它的行为似乎类似于const char* str,因此不会引起警告,因为它出现在char* 之前,但它的行为类似于char* const str

详情

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

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

在我的情况下,问题是我希望 constexpr char* str 表现得像 const char* str,而不是 char* const str,因为在视觉上它似乎更接近前者。

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

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

提示

您可以使用C gibberish ↔ English converter 将C 声明转换为易于理解的英文语句,反之亦然。这是 C 唯一的工具,因此不支持 C++ 独有的东西(如 constexpr)。

【讨论】:

以上是关于C++ 不推荐将字符串常量转换为 'char*'的主要内容,如果未能解决你的问题,请参考以下文章

请帮助:[警告]不推荐将字符串常量转换为 'char*' [-Wwrite-strings]

C ++ - 从字符串常量到'char *'的不推荐转换[重复]

如何摆脱 GCC 中“从字符串常量到‘char*’的不推荐转换”警告?

带有构造函数的简单类引发警告:ISO C++ 禁止将字符串常量转换为 'char*' [重复]

PyArg_ParseTupleAndKeywords 抛出警告:ISO C++ 禁止将字符串常量转换为‘char*’ [-Wwrite-strings]

为啥从字符串常量转换为 'char*' 在 C 中有效但在 C++ 中无效