为什么允许使用memcpy使用指向它的指针覆盖const变量?

Chr*_*ris 3 c const memcpy

为什么允许使用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变量的值.

md5*_*md5 7

尝试修改const限定变量的值会导致C中的未定义行为.您不应该依赖于您的结果,因为任何事情都可能发生.

C11(n1570),§6.7.3类型限定符

如果尝试通过使用具有非const限定类型的左值来修改使用const限定类型定义的对象,则行为是未定义的.

没有任何东西强迫编译器产生诊断消息.

实际上,这个限定符对机器代码没有太大影响.const限定变量通常不驻留在只读数据段中(显然,不在您的实现中,尽管在另一个上可能不同).

编译器无法轻易告诉指针在给定函数中指向的内容.一些静态分析工具可以执行指针分析.但是,它很难实现,将它置于标准中是愚蠢的.


Joe*_*Joe 7

问题问为什么.原因如下:

这是允许的,因为一旦你有一个指向内存地址的指针,语言就不知道它指向的是什么.它可以是变量,结构的一部分,堆或堆栈,或任何东西.所以它不能阻止你写它.直接内存访问总是不安全的,如果有另一种方法可以避免.

const你修改止损的价值const与分配(或增加等).这种突变是唯一可以保证你无法在const上执行的操作.

另一种看待这种情况的方法是静态上下文(即在编译时)和运行时上下文的划分.当你编译一段代码时,例如,可以对变量进行赋值,语言可以说"那是不允许的,它是const",这是一个编译错误.在此之后,代码被编译成可执行文件,并且它const丢失了.变量声明(以及语言的其余部分)作为输入写入编译器.编译完成后,代码就无关紧要了.你可以在编译器中做一个逻辑证明,说consts没有改变.已编译的程序运行,我们在编译时知道我们已经创建了一个不违反规则的程序.

引入指针时,您可以在运行时定义行为.您编写的代码现在无关紧要,您可以[尝试]执行您想要的操作.指针被键入的事实(允许指针算术,将指针末尾的内存解释为特定类型)意味着该语言为您提供了一些帮助,但它无法阻止您做任何事情.它无法保证,因为您可以将指针指向任何位置.编译器无法阻止您在运行时使用指针代码破坏规则.

也就是说,指针是我们获得动态行为和数据结构的方式,并且对于除了最简单的代码之外的所有代码都是必需的.

(以上内容有很多注意事项,即代码启发式,更复杂的静态分析总线广泛适用于vanilla编译器.)