在VS中更改常量char*字面值的元素

3
这是代码:
int main()  
{  
    char* a = "abc";    // Should be 'const char*', but no warnings whatsoever on VS
    a[1] = 'e';         // No warnings on VS either 

    std::cout<< a << " " << a[1];  

    return 0;  
} 

使用gcc 6.2.0编译:
>g++ -O2 -o Test Test.cpp
Test.cpp: In function ‘int main()’:
Test.cpp:5:15: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
 char* a = "abc";
           ^~~~~

>./Test
Segmentation fault (core dumped)



使用Visual Studio 2015.3编译:

>cl /EHsc /W4 /WX /O2 Main.cpp  
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86  
Copyright (C) Microsoft Corporation.  All rights reserved.  

Main.cpp  
Microsoft (R) Incremental Linker Version 14.00.24215.1  
Copyright (C) Microsoft Corporation.  All rights reserved.  

/out:Main.exe  
Main.obj   

>Main.exe  
abc e  

HUH?^

不使用/O2编译也没有警告,但运行时崩溃。


这是一个VS编译器的错误还是我漏了什么?


4
/Zc:strictStrings 是一个编译器选项,启用后会强制在字符串字面量中使用转义字符来表示特殊字符。这可以帮助开发人员避免意外的行为,例如当输入包含意外字符时可能会导致程序崩溃或安全漏洞。 - bogdan
叹气...有人知道为什么这在VS项目中默认被省略了吗?还有谁能解释一下为什么输出中a[1]e?它是一个临时变量吗? - user7079790
1
@lousybyte 在 VS 中,C++ 标准并没有完全实现,尤其是 C++11/14(甚至听说 C++98 也没有完全实现!)。也许他们仍然在某个地方使用 char* str = "foo"; 或依赖于这种行为来进行某些操作,或者出于其他一些不太合理的模糊原因 :) - Rakete1111
1
@Rakete1111编译器可以提供不会破坏符合标准的程序的扩展。 - M.M
2
编译器通常默认为最有用的模式(由编译器供应商确定),你必须使用各种开关来实现最大的标准兼容性模式。g ++也不例外,如果你不使用“-pedantic”,你会得到一堆扩展(有些好的,有些不太好的)。 - M.M
1个回答

4
我不认为这可以称之为一个 bug。使用 a[1] = 'e'; 会更改只读内存。字符串字面值不应被修改。这实际上是一种未定义的行为。为什么 VS 编译器没有像 gcc 那样发出警告呢?好吧,每个程序(编译器也是一个程序)都可以变得更好。在这种特定情况下,非常古老的编译器代码能够运行,因为这不是一个最近的 C++ 特性(比如 T&& 引用)。旧代码可能不能给出最佳错误信息。
有很多其他方式可以写糟糕的代码。不幸的是,在 C/C++ 中相对容易这样做。我们就是这样。
有许多静态代码检查器和卫士(例如:CodeSonar)。通常它们并不免费。它们能捕获很多问题,但不是所有问题。

1
我知道你不应该修改字符串常量,但在一个复杂的程序中,有人可能会意外地执行像 strcpy_s(a, 4, "xyz"); 这样的操作,而编译器不会给他任何提示,表明 a 是只读的。在 C++ 的所有陷阱和复杂性中,我认为编译器应该默认轻松捕捉到这种意外行为,而不是通过启用某些晦涩的标志来实现。 - user7079790
1
如果在您的示例中a定义为char a[4];,那么它将包含可以修改的字符串字面量副本。 - Kirill Kobelev
1
是的,但如果你在我的例子中在cout之前插入strcpy_s,程序将在运行时崩溃,并且调试器会在cout处中断,而不是在strcpy_s调用处中断。再次说明得很好,我只是觉得微软选择了这种默认行为有些愚蠢。 - user7079790

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