const 如何防止写入特定内存 [Clang, Mac OS]
How const prevents writing to specific memory [Clang, Mac OS]
我正在研究 C++,阅读一些关于使用该语言的良好习惯的书籍。我读过 const_cast
,并编写了简单的程序来回答问题:我可以去掉 const
前缀并将值写入该地址吗?
我的代码:
#include <iostream>
#include <iomanip>
int main ()
{
const int a = 5;
std::cout << std::hex << "&a = " << std::showbase << std::setfill('0') << &a << "\n";
int * b = const_cast<int *> (&a);
std::cout << std::hex << std::setfill('0') << "b = " << b << "\n";
std::cout << "Writing to address of a ..." << "\n";
*b = 10;
std::cout << "&a == b ? : " << ((&a == b) ? "True" : "False") << std::endl;
std::cout << a << std::endl;
std::cout << *b << std::endl;
return 0;
}
输出:
00:35|domin568[35] ~/Desktop/experiments/newcpp $ ./const
&a = 0x7ffee465c528
b = 0x7ffee465c528
Writing to address of a ...
&a == b ? : True
0x5
0xa
这种情况让我很好奇,他们在同一个地址上操作但他们有不同的值?让我们用 lldb 调试它!
00:37|domin568[39] ~/Desktop/experiments/newcpp $ lldb const
(lldb) b const.cpp:11
...
(lldb) r
Process 32578 launched: '/Users/domin568/Desktop/experiments/newcpp/const' (x86_64)
&a = 0x7ffeefbff478
b = 0x7ffeefbff478
Writing to address of a ...
Process 32578 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000dcb const`main at const.cpp:11
8 int * b = const_cast<int *> (&a);
9 std::cout << std::hex << std::setfill('0') << "b = " << b << "\n";
10 std::cout << "Writing to address of a ..." << "\n";
-> 11 *b = 10;
12 std::cout << "&a == b ? : " << ((&a == b) ? "True" : "False") << std::endl;
13 std::cout << a << std::endl;
14 std::cout << *b << std::endl;
Target 0: (const) stopped.
(lldb) p *b
(int) [=14=] = 5
(lldb) p b
(int *) = 0x00007ffeefbff478
(lldb) p a
(const int) = 5
(lldb) p &a
(const int *) = 0x00007ffeefbff478
(lldb) s
Process 32578 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100000dd8 const`main at const.cpp:12
9 std::cout << std::hex << std::setfill('0') << "b = " << b << "\n";
10 std::cout << "Writing to address of a ..." << "\n";
11 *b = 10;
-> 12 std::cout << "&a == b ? : " << ((&a == b) ? "True" : "False") << std::endl;
13 std::cout << a << std::endl;
14 std::cout << *b << std::endl;
15 return 0;
Target 0: (const) stopped.
(lldb) p *b
(int) = 10
(lldb) p *a
error: indirection requires pointer operand ('int' invalid)
(lldb) p a
(const int) = 10
(lldb) s
&a == b ? : True
Process 32578 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100000e34 const`main at const.cpp:13
10 std::cout << "Writing to address of a ..." << "\n";
11 *b = 10;
12 std::cout << "&a == b ? : " << ((&a == b) ? "True" : "False") << std::endl;
-> 13 std::cout << a << std::endl;
14 std::cout << *b << std::endl;
15 return 0;
16 }
Target 0: (const) stopped.
(lldb) s
0x5 <---- wtf ? changed runtime ?
有人可以向我解释一下幕后情况吗?我知道这可能是未定义的行为,但为什么会这样?
提前致谢!
C++ 中的 const
关键字是告诉编译器您不会修改变量值的方式。该值仍然可以更改,但操作 const 变量的代码不会进行更改。
通过将变量声明为 const 可以做两件事。首先,它会导致编译器仔细检查您是否没有更改 const 变量。如果您尝试修改变量,则会导致编译错误。它做的第二件事是允许编译器在优化代码时做出一些假设。
第二位可能是您程序中报告的两个值不同的原因。编译器发现 a
是 const,因此它用值 5 替换它的每次使用。要确定编译器输出的确切内容,您需要检查程序集。
正如您发现的那样,该语言确实为您提供了消除常量的方法,但这几乎从来都不是正确的做法。如您所见,使用 const_cast 可能会产生意想不到的结果。
我正在研究 C++,阅读一些关于使用该语言的良好习惯的书籍。我读过 const_cast
,并编写了简单的程序来回答问题:我可以去掉 const
前缀并将值写入该地址吗?
我的代码:
#include <iostream>
#include <iomanip>
int main ()
{
const int a = 5;
std::cout << std::hex << "&a = " << std::showbase << std::setfill('0') << &a << "\n";
int * b = const_cast<int *> (&a);
std::cout << std::hex << std::setfill('0') << "b = " << b << "\n";
std::cout << "Writing to address of a ..." << "\n";
*b = 10;
std::cout << "&a == b ? : " << ((&a == b) ? "True" : "False") << std::endl;
std::cout << a << std::endl;
std::cout << *b << std::endl;
return 0;
}
输出:
00:35|domin568[35] ~/Desktop/experiments/newcpp $ ./const
&a = 0x7ffee465c528
b = 0x7ffee465c528
Writing to address of a ...
&a == b ? : True
0x5
0xa
这种情况让我很好奇,他们在同一个地址上操作但他们有不同的值?让我们用 lldb 调试它!
00:37|domin568[39] ~/Desktop/experiments/newcpp $ lldb const
(lldb) b const.cpp:11
...
(lldb) r
Process 32578 launched: '/Users/domin568/Desktop/experiments/newcpp/const' (x86_64)
&a = 0x7ffeefbff478
b = 0x7ffeefbff478
Writing to address of a ...
Process 32578 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000dcb const`main at const.cpp:11
8 int * b = const_cast<int *> (&a);
9 std::cout << std::hex << std::setfill('0') << "b = " << b << "\n";
10 std::cout << "Writing to address of a ..." << "\n";
-> 11 *b = 10;
12 std::cout << "&a == b ? : " << ((&a == b) ? "True" : "False") << std::endl;
13 std::cout << a << std::endl;
14 std::cout << *b << std::endl;
Target 0: (const) stopped.
(lldb) p *b
(int) [=14=] = 5
(lldb) p b
(int *) = 0x00007ffeefbff478
(lldb) p a
(const int) = 5
(lldb) p &a
(const int *) = 0x00007ffeefbff478
(lldb) s
Process 32578 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100000dd8 const`main at const.cpp:12
9 std::cout << std::hex << std::setfill('0') << "b = " << b << "\n";
10 std::cout << "Writing to address of a ..." << "\n";
11 *b = 10;
-> 12 std::cout << "&a == b ? : " << ((&a == b) ? "True" : "False") << std::endl;
13 std::cout << a << std::endl;
14 std::cout << *b << std::endl;
15 return 0;
Target 0: (const) stopped.
(lldb) p *b
(int) = 10
(lldb) p *a
error: indirection requires pointer operand ('int' invalid)
(lldb) p a
(const int) = 10
(lldb) s
&a == b ? : True
Process 32578 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100000e34 const`main at const.cpp:13
10 std::cout << "Writing to address of a ..." << "\n";
11 *b = 10;
12 std::cout << "&a == b ? : " << ((&a == b) ? "True" : "False") << std::endl;
-> 13 std::cout << a << std::endl;
14 std::cout << *b << std::endl;
15 return 0;
16 }
Target 0: (const) stopped.
(lldb) s
0x5 <---- wtf ? changed runtime ?
有人可以向我解释一下幕后情况吗?我知道这可能是未定义的行为,但为什么会这样?
提前致谢!
C++ 中的 const
关键字是告诉编译器您不会修改变量值的方式。该值仍然可以更改,但操作 const 变量的代码不会进行更改。
通过将变量声明为 const 可以做两件事。首先,它会导致编译器仔细检查您是否没有更改 const 变量。如果您尝试修改变量,则会导致编译错误。它做的第二件事是允许编译器在优化代码时做出一些假设。
第二位可能是您程序中报告的两个值不同的原因。编译器发现 a
是 const,因此它用值 5 替换它的每次使用。要确定编译器输出的确切内容,您需要检查程序集。
正如您发现的那样,该语言确实为您提供了消除常量的方法,但这几乎从来都不是正确的做法。如您所见,使用 const_cast 可能会产生意想不到的结果。