为什么我可以将字符串字面值赋给char*指针?

4

我认为中的字符串文字是const char*类型。您不能将const char*对象分配给非常量char*对象。但在Visual studio 2010中,以下代码可以编译而不出错或警告,但会导致运行时错误。

int main(void)
{      
    char *str2 = "this is good";
    str2[0] = 'T';
    cout << str2;
    getchar();
    return 0;
}

如果我们不修改字符串的值,读取该值是没有问题的:

for(char *cp = str2; *cp !=0; ++cp) {
    printf("char is %c\n", *cp);
}
getch();
return 0;

为什么我们可以在这里将一个const char*赋值给char*?

@unkulunkulu 在C++中的答案略有不同:根据[lex.string],它是一个_const char_数组。 - dyp
@DyP,链接问题的答案涵盖了C++。 - unkulunkulu
@unkulunkulu 噢,抱歉,你是对的。然而,上面的代码在C++中是无效的,请参见[diff.lex]。 - dyp
@unkulunkulu请查看我用粗体突出的问题。我认为我并不是在讨论它是const char还是char,我在这里关注vc++的功能。但我认为可能是我的标题误导了您。我会进行更新。 - Joey.Z
1
@DyP - VC2010很可能不完全遵循C++11标准。 :-) 该部分是语言修订的一部分,转换在早期就被允许了(自C语言没有const的时代以来)。 - Bo Persson
显示剩余3条评论
3个回答

5
这个问题是关于VC++的,但在GCC中会有一个有意义的警告:
警告:从字符串常量到 'char *' 的过时转换 [-Wwrite-strings]
这个警告意味着即使有const和非const之间的差异,编译器仍会应用隐式转换。因此,这段代码没有任何运行时修改也是可以的:
char *str2 = "this is good";

然而,修改str2会导致未定义的行为。

1
字符串字面量确实是常量。但是,数组会衰减为指针,并且您使用了指向数组第一个元素的非const指针:
char *str2 = "this is good";

修改const char数组的任何值都会产生未定义的行为。
在gcc 4.7.2下,这将无法编译通过。如果你在MSVC下将警告级别提高到4级,它可能也会发出警告。

[diff.lex] 明确指出在 C++ 中 char* p = "abc"; 是无效的。现在我很困惑。 - dyp
@Dyp 在vc++中是有效的,但你不能修改该值。 - Joey.Z
所以MSVC将字面值视为char*,是吗? - Joey.Z
1
我刚刚发现MSVS 2013不会将此报告为错误,无论是使用/W4还是/Wall/Wall/W4都不行 - 这太过分了!我不确定/W4/Wall之间的区别是什么:两者都被描述为几乎最大化。 - PJTraill
奇怪的是,MSVS代码分析有一个规则C6298,我认为我正在应用它(通过“ AllRules”),但在返回char *的函数中使用return“?”;时却没有触发该规则。 - PJTraill
MSVS 的疯狂之处在于,即使启用了字符串池化,这种情况仍然会发生。 - PJTraill

1
让我们看看C++03而不是C++11:

(保留html)

[conv.array]

一个非宽字符串字面值(2.13.4)可以转换为类型为“指向char的指针”的rvalue;

实际上,任何窄字符串字面值都是“n个const char的数组”类型,但正如您可以在上面阅读到的那样,有一个(在C++03中已弃用)功能将其隐式转换为类型为char *的rvalue。

但您仍然不允许更改字符串内容,就像您进行了const_cast一样:指针所指向的对象已声明为const,因此不允许修改(未定义行为)。


不错!所以,它仍然是const char*,但有一个隐式转换。明白了! - Joey.Z
@zoujyjs 差不多。有两个转换。[conv.array],括号里是我的文字说明:将 "abc" 从一个由4个const char组成的数组 [array of 4 const char] 转换为指向const char的指针 [pointer to const char],这是一个数组到指针的转换;然后再进行一次限定符转换,将其转换为指向char的指针 [pointer to char]。 - dyp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接