为啥从字符串常量转换为 'char*' 在 C 中有效但在 C++ 中无效
Posted
技术标签:
【中文标题】为啥从字符串常量转换为 \'char*\' 在 C 中有效但在 C++ 中无效【英文标题】:Why is conversion from string constant to 'char*' valid in C but invalid in C++为什么从字符串常量转换为 'char*' 在 C 中有效但在 C++ 中无效 【发布时间】:2014-01-23 13:13:26 【问题描述】:C++11 标准 (ISO/IEC 14882:2011) 在 § C.1.1
中说:
char* p = "abc"; // valid in C, invalid in C++
对于 C++ 来说,这是可以的,因为指向字符串文字的指针是有害的,因为任何修改它的尝试都会导致崩溃。但为什么它在 C 中有效?
C++11 还说:
char* p = (char*)"abc"; // OK: cast added
这意味着如果将强制类型转换添加到第一条语句,它就会变得有效。
为什么强制转换使第二个语句在 C++ 中有效,它与第一个语句有何不同?不还是有害吗?如果是这样,为什么标准说没问题?
【问题讨论】:
C++11 不允许第一个。我不知道为什么 C 首先将字符串文字char[]
设为类型。第二个是伪装的const_cast
。
如果更改此规则,将会破坏的遗留 C 代码太多。
C 语言在有const
之前就有字符串文字,所以它们不一定是const
。
C 和 C++ 允许您从几乎任何类型转换为另一种类型。这并不意味着这些演员表是有意义和安全的。
更重要的是,这个问题必须源于某种想法,即这两种语言比它们有更多的共同点。错误消息证明这是不正确的,那么为什么您认为询问这两种语言是个好主意,就好像您希望它们有一个共同的子集一样?在那个公共子集中编程是在浪费你的时间。你将依靠两全其美。选择其中一个,当您需要链接来自不同语言的模块时使用链接器。
【参考方案1】:
在 C++03 之前,您的第一个示例是有效的,但使用了已弃用的隐式转换——字符串文字应被视为 char const *
类型,因为您无法修改其内容(不会导致未定义行为)。
从 C++11 开始,已弃用的隐式转换已被正式删除,因此依赖它的代码(如您的第一个示例)不应再编译。
您已经注意到允许代码编译的一种方法:虽然隐式转换已被删除,但 显式 转换仍然有效,因此您可以添加强制转换。但是,我不会考虑这种“修复”代码。
真正修复代码需要将指针的类型更改为正确的类型:
char const *p = "abc"; // valid and safe in either C or C++.
至于为什么它在 C++ 中被允许(并且仍然在 C 中):仅仅因为有很多现有代码依赖于隐式转换,并且破坏该代码(至少没有一些官方警告)显然似乎标准委员会是个坏主意。
【讨论】:
@rullof:这很危险,它没有提供任何有意义的灵活性,至少对于(完全)关心可移植性的代码来说。写入字符串文字通常会使您的程序在现代操作系统上中止,因此允许代码(尝试)在那里写入不会增加任何有意义的灵活性。 这个答案char const *p = "abc";
中给出的代码 sn-p 是“在两个 C 和 C++中都有效且安全”,而不是“有效且在任一 C 或 C++”中都是安全的。
@DanielLe 这两个句子意思一样
天哪! [将舌头牢牢插在脸颊上]对不起,“或”在这里是正确的术语。代码可以编译为 C 或 C++,但不能同时编译为 C 和 C++。你可以选择任何一个,但你必须做出选择。你不能同时拥有两者。 [恢复正常的舌头操作]。
不,both/and 是这里最清晰、最正确的措辞。 Either/or 也恰好传达了正确的含义,但在技术上并不那么清楚。 或单独是无可辩驳的错误(A or B不等于A and B)。【参考方案2】:
由于历史原因,它在 C 中有效。 C 传统上指定字符串文字的类型是 char *
而不是 const char *
,尽管它通过说实际上不允许修改它来限定它。
当您使用强制转换时,您实际上是在告诉编译器您比默认类型匹配规则更了解,并且它使赋值正常。
【讨论】:
原来是char[N]
,后来改成了const char[N]
。它附有尺寸信息。
在 C 中,字符串文字的类型是 char[N]
,但不是 char*
,例如"abc"
是 char[4]
【参考方案3】:
你也可以使用strdup:
char* p = strdup("abc");
或
char p[] = "abc";
正如here所指出的那样
【讨论】:
请注意"abc"
被重复,指针 p
应该是 free
d 以避免内存泄漏。
我原本想做一个简单的演员char* p = (char*)"abcXXXXX";
,但我的程序崩溃了,因为我实际上是在稍后修改字符串(我正在使用mkstemp
来替换X)。这个解决方案奏效了。而且我没有忘记free(p)
。
我相信提问者知道这一点;问题是为什么 C和C++在这里有不同的规则。【参考方案4】:
您可以声明如下选项之一:
char data[] = "Testing String";
或
const char* data = "Testing String";
或
char* data = (char*) "Testing String";
【讨论】:
我相信提问者知道这一点;问题是为什么 C和C++在这里有不同的规则。以上是关于为啥从字符串常量转换为 'char*' 在 C 中有效但在 C++ 中无效的主要内容,如果未能解决你的问题,请参考以下文章
C++ 警告:不推荐使用从字符串常量到“char*”的转换 [-Wwrite-strings]
如何摆脱 GCC 中“从字符串常量到‘char*’的不推荐转换”警告?