下面的代码使用Xcode 11.3.1中的默认设置可以很好地编译:
#include <stdio.h>
int main(int argc, const char * argv[]) {
char* thing = "123";
thing[2] = '4';
printf("%s\n", thing);
return 0;
}
但是,在运行时,代码会在thing[2] = '4'
上使用EXC_BAD_ACCESS捕获。我假设这是因为表示"123"
的字节的内存被编译到我的程序的二进制文件中的某个地方,在现代处理器/操作系统上被标记为code rather than data。(This answer证实了这一点--更不用说反汇编中有一行leaq 0x4d(%rip), %rsi ; "123"
,它将指针传递到相对于指令指针的地址!)
C语言允许这样做只是一个历史产物,来自自我修改代码的时代吗?我注意到我也可以分配void* x = main;
,而不会抱怨我丢弃了修饰符。
This answer说:
根据C99的基本原理,委员会中有人希望字符串文字是可修改的,所以标准没有明确禁止它。
我能读到关于这一点的进一步讨论吗?更实际的是,有没有一种方法可以告诉clang和/或gcc标记这样的赋值(即使它们实际上并不被禁止)并发出警告,而不需要编译为C++?
3条答案
按热度按时间nwnhqdif1#
你引用的答案是一个没有引用的观点,坦率地说是胡说八道。它只不过是不破坏大量现有的遗留C代码,希望在现代编译器中保持可编译性。
然而,如果你设置了必要的警告级别或选项,许多编译器会发出警告。在GCC中:
-Wwrite-strings
在编译C时,给予字符串常量指定
const char[length]
类型,以便将一个的地址复制到非constchar*
指针中会产生警告。这些警告可以帮助您在编译时找到可能尝试写入字符串常量的代码,但前提是您必须非常小心地在声明和原型中使用const
。否则,它只是一个麻烦。这就是为什么我们没有让-Wall
请求这些警告的原因。编译C时,警告从字符串字面量到char * 的转换已被弃用。对于C程序,默认情况下启用此警告。
CLANG也有
-Wwrite-strings
,其中是-Wwriteable-strings
的同义词-Wwritable-strings
默认情况下启用此诊断。
还控制
-Wdeprecated-writable-strings
。诊断文本:
C编译的诊断文本是不同的-我只是引用手册。
在使用
-Wwrite-strings
的GCC中:生产:
CLANG生产:
cpjpxq1n2#
与C相反,在C中,字符串字面量具有非常量字符数组的类型。
然而,根据C标准,任何修改字符串文字的尝试都会导致未定义的行为。
历史上,C语言没有限定符const。const这个限定符最早出现在C中。因此,为了向后兼容,C中的字符串字面量具有非常量字符数组的类型。
w8f9ii693#
你有-Wwrite-strings:
在编译C时,给予字符串常量类型const char[length],以便将一个的地址复制到非const char * 指针中会产生警告。这些警告可以帮助您在编译时找到可能尝试写入字符串常量的代码,但前提是您必须非常小心地在声明和原型中使用const。否则,它只是一个麻烦。这就是为什么我们没有提出-墙要求这些警告。