【问题标题】:How const prevents writing to specific memory [Clang, Mac OS] [duplicate]const 如何防止写入特定内存 [Clang,Mac OS] [重复]
【发布时间】:2019-02-20 20:45:53
【问题描述】:

我在搞乱 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) $0 = 5
(lldb) p b
(int *) $1 = 0x00007ffeefbff478
(lldb) p a
(const int) $2 = 5
(lldb) p &a
(const int *) $3 = 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) $4 = 10
(lldb) p *a
error: indirection requires pointer operand ('int' invalid)
(lldb) p a
(const int) $5 = 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++ constants const-cast


    【解决方案1】:

    C++ 中的const 关键字是告诉编译器您不会修改变量值的方式。该值仍然可以更改,但对 const 变量进行操作的代码不会进行更改。

    通过将变量声明为 const 可以做两件事。首先,它会导致编译器仔细检查您是否没有更改 const 变量。如果您尝试修改变量,则会导致编译错误。它所做的第二件事是允许编译器在优化代码时做出一些假设。

    这第二点可能是程序中报告的两个值不同的原因。编译器发现 a 是 const,因此它将每次使用它都替换为值 5。要确定编译器输出的确切内容,您需要检查程序集。

    正如您所发现的,该语言确实为您提供了删除 const 的方法,但它几乎从来都不是正确的做法。如您所见,使用 const_cast 可能会产生意想不到的结果。

    【讨论】:

    • 还有更多内容。如果对象是非 const 并作为 const 参数传递,那么您可以 const_cast 摆脱 const-ness 并在函数中写入它。如果对象是const,那么你不能const_cast 离开常量。后者是未定义的行为。 OP的int是const int a = 5;,所以const不能是const_cast。这里有一个很好的问答,但我找不到。
    • 确实如此。我认为,仅仅因为你可以在某些情况下合法地抛弃const 并不意味着你应该这样做。在大多数情况下,我希望重构代码,或者实现不接受 const 的第二个函数,这将是一条更可取的前进道路。
    猜你喜欢
    • 2019-06-21
    • 2019-01-17
    • 2020-04-29
    • 2020-11-04
    • 1970-01-01
    • 2012-11-11
    • 2018-01-27
    • 2017-11-22
    • 1970-01-01
    相关资源
    最近更新 更多