在Visual Studio 2015中,以下编译:
strcpy("destination", "Source");
编译器不应该知道"目的地"是文字,不能构成有效的非const char *参数?
作为旁注,它确实"正确"在它运行时崩溃。
答案 0 :(得分:6)
字符串文字在C中一直是非const的。当前的标准草案n1570在6.4.5 / 6中说:
多字节字符序列[由相邻字符串文字的连接产生,-ps]然后用于初始化静态存储持续时间的数组,并且长度足以包含序列。对于字符串文字,数组元素具有 键入char [而不是const char,-ps]。
原因当然,原来他们 确实通常是可写的。该计划本身是可写的;甚至还有自我修改的代码。这是相关的,因为字符串文字是由编译器“与程序一起”生成和存储的。
现代内存管理 - 即高级机器架构的问题 - 这使得在访问程序的内存时可以生成硬件异常。使用这种可能性是一个安全问题。并非所有体系结构(都可以)都这样做,即使在今天,编译器也可以选择控制字符串的位置(例如-fwritable-strings
使用旧的gcc)。
在语法上,代码是兼容的,在语义上它是n1570中每6.4.5 / 7的UB:“如果程序试图修改这样的数组,行为是 未定义。“
当字符串文字的地址被分配给非常量变量时(或者用于在函数调用中初始化非常量参数),编译器可以发出警告,但是我尝试的常见变量并没有警告哪些让我感到困惑 - a许多已实施的警告似乎不那么重要和吵闹。
关于strcpy()
的细节:有些评论说“编译器不知道strcpy()
做了什么”。这往往是误导性的:
lint
这样的工具通常知道这种语义。 确实,gcc happens to replace strcpy
and many other functions with built-ins,所以它确实有第一手信息,第一个地址将被写入。它只是不使用它。
另一个gcc内在函数是printf()
,这里编译器使用它的printf
语义知识来警告格式错误。这清楚地表明,strcpy()
也可以发出警告。
顺便说一句,gcc 警告"abc"[1] = 0;
。这很有趣,因为我曾认为strcpy()
内在函数会被内联(它必须很短),以便-O3
和-flto
在某个时刻相当于"destination"[i] = "Source"[i];
实际上对于编译器是可见的并触发相同的警告。
我测试了VC 2013,gcc 5.3.0,gcc 4.7.2和clang 3.7.1。它们都没有发出将字符串文字传递给strcpy()
的警告,但是cremno指出VC提供了捕获错误的/analyze
选项。