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 的正确性,您的程序中缺少一个或多个 const
s。但是您向我们展示的代码不是问题,因为它没有进行这种已弃用的转换。警告一定来自其他地方。
【讨论】:
不幸的是,考虑到对这个问题的看法和投票,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我也遇到了同样的问题。而我所做的只是添加 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* str
和char* 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]