为什么允许使用memcpy指向它的指针更改const变量?
这段代码:
const int i=5;
int j = 0;
memcpy(&j, &i, sizeof(int));
printf("Source: i = %d, dest: j = %d\n", i,j);
j = 100;
memcpy(&i, &j, sizeof(int));
printf("Source: j = %d, dest: i = %d\n", j,i);
return 0;
Run Code Online (Sandbox Code Playgroud)
编译只是一个警告:
警告:传递'memcpy'的参数1从指针目标类型中丢弃'const'限定符[默认启用]
但确实运行得很好,并改变了const变量的值.
问题问为什么.原因如下:
这是允许的,因为一旦你有一个指向内存地址的指针,语言就不知道它指向的是什么.它可以是变量,结构的一部分,堆或堆栈,或任何东西.所以它不能阻止你写它.直接内存访问总是不安全的,如果有另一种方法可以避免.
在const
你修改止损的价值const
与分配(或增加等).这种突变是唯一可以保证你无法在const上执行的操作.
另一种看待这种情况的方法是静态上下文(即在编译时)和运行时上下文的划分.当你编译一段代码时,例如,可以对变量进行赋值,语言可以说"那是不允许的,它是const",这是一个编译错误.在此之后,代码被编译成可执行文件,并且它const
丢失了.变量声明(以及语言的其余部分)作为输入写入编译器.编译完成后,代码就无关紧要了.你可以在编译器中做一个逻辑证明,说const
s没有改变.已编译的程序运行,我们在编译时知道我们已经创建了一个不违反规则的程序.
引入指针时,您可以在运行时定义行为.您编写的代码现在无关紧要,您可以[尝试]执行您想要的操作.指针被键入的事实(允许指针算术,将指针末尾的内存解释为特定类型)意味着该语言为您提供了一些帮助,但它无法阻止您做任何事情.它无法保证,因为您可以将指针指向任何位置.编译器无法阻止您在运行时使用指针代码破坏规则.
也就是说,指针是我们获得动态行为和数据结构的方式,并且对于除了最简单的代码之外的所有代码都是必需的.
(以上内容有很多注意事项,即代码启发式,更复杂的静态分析总线广泛适用于vanilla编译器.)