为啥从字符串常量转换为 '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 应该是 freed 以避免内存泄漏。 我原本想做一个简单的演员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++ 中无效的主要内容,如果未能解决你的问题,请参考以下文章

从字符串常量到 'char*' 的折旧转换

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

C++ 警告:不推荐使用从字符串常量到“char*”的转换 [-Wwrite-strings]

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

为啥字符串函数有一些参数作为 const char *(指向常量字符的指针)?

C语言整型转换问题?