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 可能会产生意想不到的结果。