【问题标题】:How internally this works int const iVal = 5; (int&)iVal = 10;这在内部是如何工作的 int const iVal = 5; (int&)iVal = 10;
【发布时间】:2009-03-19 08:47:24
【问题描述】:

我想知道以下在编译器级别是如何工作的。

int const iVal = 5; 
(int&)iVal = 10; 

一点 m/c 或编译器级别的答案会很完整。

提前致谢。

【问题讨论】:

  • 您必须在第一行指定 iVal 的类型。
  • 您的语法不正确 - iVal 声明缺少类型,并且 (int&) 无效(至少在 C 中)。
  • 对不起,伙计们:)。非常感谢 Iraimbilanja :)

标签: c++ c compiler-construction


【解决方案1】:

undefined behavior

在第一行你定义一个常量整数。此后,在您的程序中,编译器只允许将 iVal 替换为值 5。它可能会改为从内存中加载它,但可能不会,因为这不会带来任何好处。

第二行写入您的编译器告诉您包含数字 5 的内存位置。但是,这不能保证有任何效果,因为您已经告诉编译器该值不会改变。

例如,下面将定义一个 5 元素的数组,并打印一个未定义的值(或者它可以做任何事情!它是未定义的)

int const iVal = 5;
(int&)iVal = 10;
char arr[iVal];
cout << iVal;

生成的程序集可能类似于:

sub ESP, 9      ; allocate mem for arr and iVal. hardcoded 5+sizeof(int) bytes
                ; (iVal isn't _required_ to have space allocated to it)
mov $iVal, 10   ; the compiler might do this, assuming that you know what
                ; you're doing. But then again, it might not.
push $cout
push 5
call $operator_ltlt__ostream_int
add ESP, 9

【讨论】:

    【解决方案2】:

    C 风格的转换充当 const_cast。就像你写的一样

    const_cast<int&>( iVal ) = 10;
    

    如果您碰巧这样做并且编译器决定不为 iVal 分配实际内存,则会遇到未定义的行为。

    比如VC7编译就可以了。它甚至可以在调试模式下运行。在 Release 模式下,iVal 值在赋值后不会改变 - 它仍然是 5。

    所以你永远不应该这样做。

    【讨论】:

      【解决方案3】:

      为什么不通过你的 cown 编译器运行它并查看汇编输出?

      【讨论】:

      • Neil,VC7 编译好了。它甚至可以在调试模式下运行。在 Release 模式下,iVal 值不会改变。
      • 因无缘无故被否决而被赞成。这篇文章很有意义——如果 OP 真的想知道(我怀疑)编译器生成什么代码,反汇编编译器输出是最好的方法。
      • 因为这是未定义的行为,所以允许不同的编译器做不同的事情——一个编译器的结果相对没用。
      • @snemarch - 提问者专门询问机器代码,所以这似乎是最好的解决方案。我知道代码是非法的,我最初的回复指出了这一点——我对此投了反对票——你赢不了!
      • 不要担心投反对票的人。我会再次投票给你和其他人,我敢肯定。我的意思是当他有无效的 C++ 代码并询问它是如何在内部“工作”时有什么帮助?
      【解决方案4】:

      这是可能的,因为“const-ness”的概念只存在于语言/编译器中。在实际的计算机内存中,一切都是可变的。编译代码后,您的 iVal 变量只是 RAM 中的一个位置。

      edit:上面假设常量实际上是放在内存中的。见sharptooth's answer

      使用 c 风格的强制转换告诉编译器将此内存位置视为一个简单的整数变量,并将该值设置为 10。

      【讨论】:

      • 编译器可能会将 const 放入只读内存段(如果操作系统支持),所以这不仅仅是语言问题。
      【解决方案5】:

      未定义的行为。

      在发布版本中,大多数编译器将直接替换 const 值 - 但您可能遇到执行内存加载的编译器。此外,第二个分配可能会也可能不会产生访问冲突,具体取决于平台和编译器。 Iirc Intel 的编译器将 const 数据放在只读内存中,因此会在运行时产生访问冲突。

      【讨论】:

        【解决方案6】:

        如果这是一个嵌入式系统,iVal 很可能会存储在闪存中,因此写入它不会有任何效果。

        但是,编译器可能不会将此视为错误,因为嵌入式编译器通常不会跟踪特定内存区域是否可读。

        我怀疑它也可能通过链接器,因为链接器通常会确定 iVal 是一个常量,所以会在闪存中使用 - 但确定 iVal 的使用方式并不是链接器的工作。

        顺便说一句,这个问题被标记为“C”,但“(int&)”语法不是 (AFAIK) 有效的 C。但是,同样可以通过以下方式实现:

        int *Ptr = (int *) &iVal;
        *Ptr = 10;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-08-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-11
          相关资源
          最近更新 更多