C++ 全局常量写入上的Segfault
考虑以下代码:C++ 全局常量写入上的Segfault,c++,C++,考虑以下代码: const int x = 5; int main() { int* p = const_cast<int*>(&x); *p = 10; return 0; } const int x=5; int main(){ int*p=const_cast(&x); *p=10; 返回0; } 它会导致分割错误。现在考虑这个问题: int main() { const int x = 5; int* p = c
const int x = 5;
int main() {
int* p = const_cast<int*>(&x);
*p = 10;
return 0;
}
const int x=5;
int main(){
int*p=const_cast(&x);
*p=10;
返回0;
}
它会导致分割错误。现在考虑这个问题:
int main() {
const int x = 5;
int* p = const_cast<int*>(&x);
*p = 10;
return 0;
}
intmain(){
常数int x=5;
int*p=const_cast(&x);
*p=10;
返回0;
}
它很好用
在这两种情况下都有未定义的行为:只有当对象确实引用了可变对象时,才允许丢弃
const
。对于作为const
对象开始使用的对象,不允许丢弃const
。这些对象可能存在于只读内存中(在第一个示例中显然是这样),但这不是必需的(在第二个示例中显然是这样)。在这两种情况下都有未定义的行为:只有当对象确实引用了可变对象时,才允许丢弃const
。对于作为const
对象开始使用的对象,不允许丢弃const
。这些对象可能存在于只读内存中(第一个示例中的情况很明显),但这不是必需的(第二个示例中的情况很明显)。当您使用常量时,您告诉编译器,它可以更自由地处理对象,以换取您的承诺,您永远不会试图更改它。当你违背诺言时,你就进入了行为不明确的领域
有时,编译器会通过创建代码来响应,这样您就可以丢弃常量,一切都会很好——就好像它从一开始就不是常量一样。然而,这很像是“幸运地”你的代码工作
在一个不可变的对象上丢弃const
是不安全的。当您使用const
时,您告诉编译器,它可以更自由地处理对象,以换取您的承诺,您永远不会试图更改它。当你违背诺言时,你就进入了行为不明确的领域
有时,编译器会通过创建代码来响应,这样您就可以丢弃常量,一切都会很好——就好像它从一开始就不是常量一样。然而,这很像是“幸运地”你的代码工作
<> >在不可变的对象上丢弃<代码> const <代码>永远是不安全的。 < p> C++运行时有两种类型的内存,只读和读写。编译时常量放在只读内存中,即使使用强制转换也无法更改。。这里const是一个硬件限制,并写入segfaults。自动变量(函数范围变量)放在堆栈上,堆栈是读写内存。这里const是一个软件限制,绕过该限制可以进行写操作
只读内存与读写内存的最简单示例是字符串常量:
char *p = "string"; p[0] = 'a'; // segfault
char q[] = "string"; q[0] = 'a'; // "atring"
C++运行时有两种类型的内存,只读和读写。编译时常量放在只读内存中,即使使用强制转换也无法更改。。这里const是一个硬件限制,并写入segfaults。自动变量(函数范围变量)放在堆栈上,堆栈是读写内存。这里const是一个软件限制,绕过该限制可以进行写操作
只读内存与读写内存的最简单示例是字符串常量:
char *p = "string"; p[0] = 'a'; // segfault
char q[] = "string"; q[0] = 'a'; // "atring"
在这两种情况下都是未定义的行为,任何情况都可能发生写入只读数据/代码段(如全局常量)会生成SEGFULT。在堆栈段中写入值(因为它是本地常量)不会生成segfault。不管怎样,这都是愚蠢的。带有bug的代码会做奇怪的事情。在这两种情况下都是未定义的行为,任何事情都可能发生编写只读数据/代码段(如全局常量)会生成segfault。在堆栈段中写入值(因为它是本地常量)不会生成segfault。不管怎样,这都是愚蠢的。带有bug的代码会做奇怪的事情。修复错误,神秘感就会消失。