使用地址解释强制转换const

C++ - Casting const by using the address explanation

本文关键字:转换 const 解释 地址      更新时间:2023-10-16

我用c++写了下面的代码:
我想对const变量进行类型转换,然后改变它,这是代码:

#include <iostream>
using namespace std;
int main()
{
    int const a = 5;
    int* ptr = (int*)&a;
    *ptr = 10;
    cout<<"a is : "<< a << endl;
    system("pause");
}

这段代码通过了编译器,我希望程序能打印在屏幕上10,
但是屏幕显示的结果是5。
当我运行调试器时,&a中的内存已经像我预期的那样更改为10。
知道为什么吗?

首先这是未定义行为。不要这样做。其次,当您打印出a时,编译器实际上在查看&a的内存,因为您告诉编译器a永远不会改变(您说它是const)。所以它实际上变成了…

cout << "a is : "<<5 << endl;

你正在调用未定义的行为与问题的代码,试图改变一个变量声明为const的cast away constness是不允许的(除非const变量真的是一个变量不是const的引用)。

对您的结果的一个合理且极有可能的解释是,编译器知道a的值不应该改变,因此它几乎可以将a的所有出现替换为5。ie。"查找"被优化掉了。

为什么要查看a的地址来读取它的值,当它被声明为始终是5时?


让我们看一下编译器可能将代码段转换成的指令

foo.cpp

void func (int)
{
  /* ... */
}
int
main (int argc, char *argv[])
{
  const int a = 10; 
  int * p     = &const_cast<int&> (a);
  *p = 20; 
  func (a);
}

<一口>

main的汇编指令由g++ -S foo.cpp给出
main:
.LFB1:
  .cfi_startproc
  pushq %rbp
  .cfi_def_cfa_offset 16
  .cfi_offset 6, -16 
  movq  %rsp, %rbp
  .cfi_def_cfa_register 6
  subq  $32, %rsp
  movl  %edi, -20(%rbp)
  movq  %rsi, -32(%rbp)
  movl  $10, -12(%rbp)
  leaq  -12(%rbp), %rax
  movq  %rax, -8(%rbp)
  movq  -8(%rbp), %rax # store the adress of `a` in %rax
  movl  $20, (%rax)    # store 20 at the location pointed to by %rax  (ie. &a)
  movl  $10, %edi      # put 10 in register %edi (placeholder for first argument to function)
                       # # notice how the value is not read from `a`
                       # # but is a constant
  call  _Z4funci       # call `func`
  movl  $0, %eax
  leave
  .cfi_def_cfa 7, 8
  ret 
  .cfi_endproc

如上所示,20的值确实被放在%rax中存储的地址,其中(%rax)包含a (movl $20, (%rax))的地址,但是我们调用void func (int)的参数是常数10 (movl $10, %edi)。

如前所述;编译器假定a的值不会改变,而不是每次使用a时都读取内存位置,而是将其替换为常量值10