【问题标题】:Changing value of const by pointer通过指针改变 const 的值
【发布时间】:2017-03-15 18:16:10
【问题描述】:

this question 上的 answer 解释了如何通过取消引用指向其地址的指针来更改常量变量(显然是通过创建新变量)。

const int i = 10;
*(int *)&i = 5;

std::cout << &i << "\t" << i << "\n";                   // 0x7fff6b325244   10

std::cout << &*(int *)&i << "\t" << *(int *)&i << "\n"; // 0x7fff6b325244   5

使用&amp;*(int *)&amp;i,我试图获取上一个答案所讨论的新变量的地址。如何找到这个新变量的存储位置?

*(int *)&amp;i 显示不同的值,因此必须有一个新变量。

在 g++ 5.4.0、Ubuntu 16.04 上编译

【问题讨论】:

  • 未定义的行为。
  • 有很多去引用和重新引用。小心。
  • @AdityaGulavani 这就是未定义行为的定义——你无法预测的行为。
  • 推理未定义的行为是浪费时间。
  • "正在显示不同的值,因此必须有一个新变量。" -- 不,没有。由于您对编译器撒谎并告诉它 i 的值永远不会从 10 更改,因此在您请求 i 的值的任何地方都可以简单地使用常量值 10。它不需要变量。

标签: c++ c constants


【解决方案1】:

更改声明为const 的变量的值时的行为未定义。编译器不必做任何有意义的事情。

在这种情况下,编译器在打印consti 时不会费心查看内存,因为它知道该值不可能被任何符合要求的代码更改。当你打印i 时,它会生成这个程序集:

mov     esi, 10
mov     rdi, rax
call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)

请注意,它只是在该调用中硬编码10

【讨论】:

  • 我目前也在探索将其声明为 volatile 的效果。如果你能在这个想法上加两分钱,那就太好了
  • @AdityaGulavani:const 说明符意味着您告诉编译器标识符中的值不会改变。 volatile 说明符意味着变量的值可以通过程序执行之外的方式(其他线程、硬件寄存器等)进行更改。你不能有volatileconst,因为它没有意义。
  • 请注意,常量可能会出现在可执行文件内的只读部分中,即使您尝试写入 const 变量的地址(假设有一个),操作系统也会终止您的进程出现访问冲突错误,因为您尝试写入只读页面。
  • @ThomasMatthews 该标准没有禁止声明const volatile T,但是在稍微梳理了文档之后,我仍然无法告诉您这样的构造应该是什么意思。我最好的猜测是它的意思是“它的价值可能会改变,但你不能改变它”。
  • 就“volatile const”而言:volatile const i = 0;易失性 int *p = &i; *p = 2; MSVC 2015 和 GCC 5 都会发出警告。两者都将生成写入 i 的地址的代码(禁用优化)。奇怪的是,我将被放置在 PE 内的读写部分中。但这没有任何意义,与其他版本/设置一样,生成的可执行文件可能会有很大不同。它会起作用并改变我的价值。
【解决方案2】:

正如原始答案正确指出的那样:

这是“未定义的行为”,这意味着根据标准,您无法预测尝试此操作时会发生什么。根据特定的机器、编译器和程序的状态,它可能会做不同的事情。

任何事情都是公平的游戏,包括您所观察到的,这可能只是编译器优化的结果。您不应该花太多时间试图解释未定义的行为。

编辑:为了更清楚地了解建议:不要这样做

【讨论】:

  • 是的,我从不这样做。我只是想知道当这样的事情出现时的底层编译器行为
  • @AdityaGulavani 即使在同一程序的两次编译之间,编译器行为也可能不一致。几乎可以肯定,不同的编译器之间会有所不同。您可以做的一件事是列出在简单情况下最可能的行为,但这并不是真正有用的。附:您是否已在实验中遇到尝试写入写保护页面错误?
  • 还没有,听说了,想去探索一下:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多