【问题标题】:What does casting do at compiler/machine level?强制转换在编译器/机器级别有什么作用?
【发布时间】:2009-03-24 08:12:15
【问题描述】:

我经常想知道强制转换在编译器或机器级别究竟做了什么。内存中的 0 和 1 有什么作用?

谁能指点我一些好的文学作品。

【问题讨论】:

    标签: java compiler-construction casting


    【解决方案1】:

    在引用类型之间进行转换时,转换不会修改各个位,它只是指示编译器/运行时在可能的情况下以特定方式解释位。

    如果由于类型不兼容而在编译时无法进行强制转换,则会发出错误。如果在运行时无法进行强制转换,则会引发异常。

    wiki page on type conversion 有更多信息。

    【讨论】:

    • 这仅适用于非数字转换
    • 类转换异常检查必须以某种方式插入到字节码中,确定吗?
    【解决方案2】:

    在 C 中,对于非数字类型,强制转换对内存中的 0 和 1 没有任何作用。

    对于数值类型,C 编译器会进行转换,以使数值尽可能保持不变。

    如果您确实想在不更改位值的情况下转换数字类型,则必须使用联合或转换指针(以下代码说明了后者):

    float a;
    int b = 3;
    
    a = *((float*)&b);
    

    【讨论】:

      【解决方案3】:

      关于 Casting,一个有用的文献是 JavaTM Virtual Machine Specification

      Conversions and Promotions 部分,您会看到有六大类转换:

      • 身份转换
      • 扩大基元转换
      • 缩小原始转换范围
      • 扩大参考转化率
      • 缩小参考转换范围
      • 字符串转换

      有五种转换上下文可以出现转换表达式,包括Casting Conversion

      铸造上下文允许使用:

      • 身份转换,
      • 一个扩大的基元转换,
      • 一个缩小的原始转换,
      • 扩大参考转换,或
      • 缩小参考转换。

      因此,强制转换比赋值或方法调用转换更具包容性:强制转换可以进行除字符串转换之外的任何允许的转换。

      强制转换可以将任何数值类型的值转换为任何其他数值类型。 boolean 类型的值不能转换为另一种类型。引用类型的值不能转换为原始类型的值。

      某些类型转换可能在编译时被证明不正确并导致编译时错误。否则,可以在编译时证明强制转换是正确的,或者需要运行时有效性检查。 (有关详细信息,请参阅JavaTM Language Specification。)
      如果运行时的值为空引用,则允许强制转换。如果运行时检查失败,则抛出 ClassCastException。

      【讨论】:

        【解决方案4】:

        其他人已经介绍了基础知识,但我想就如何实现编译器说几句话,这可能对他的情况有所启​​发。

        编译器维护一个列表(称为符号表)在程序中的任何特定点使用的变量名称和一些关于变量的信息。信息列表包括:

        • 它们分配的存储空间(在此寄存器中、在该内存位置等...)
        • 它们是什么类型(即整数或字符串或SubWhatsitObj),包括任何限制(例如恒定性)
        • 编译器需要的任何链接信息

        编译器使用此信息来决定如何处理涉及变量的表达式。存储在符号表中的元信息类型也可以从它的组件中为任何表达式派生出来。

        除了数值类型转换的特殊情况外,强制转换只是告诉编译器对变量或表达式使用不同的元信息,而不是通常的情况。内存中的任何位都不会受到影响,但计算的结果可能会受到影响。

        【讨论】:

          【解决方案5】:

          假设这只是一个引用类型转换而不是转换(例如 int 到 byte),我相信它会执行以下操作:

          1) 检查引用是否为空 - 如果是,则退出。 2)按照引用找到内存中的对象。在对象头中,有说明类型是什么的信息。 3) 从类型信息中,检查目标类型是否在层次结构中。如果不是,请发送ClassCastException 并提供适当的信息。

          结果的“位”总是与输入的“位”相同(假设 输出而不是异常),但是 JVM 知道参考,以保证其他操作成功。

          【讨论】:

            【解决方案6】:

            还需要了解引用在编译和运行时是如何工作的。

            每种类型都有一个查找表,用于解决每种方法 每个方法到该类型最解析的方法。

            因此,如果您的引用是一个对象,则调用 toString() 会做正确的事情并找到最派生的 toString() 方法。强制转换对于允许运行时保证任何给定的引用确实具有引用上公开的每个方法的目标方法是必要的。在将类型转换从 X 传递到 Y 之后,可以确保任何类型 Y 的引用都可以在 casted(sp) 引用中使用。

            【讨论】:

              【解决方案7】:

              这取决于你施放什么。对于数字转换,(从浮点数到整数并返回),CPU 将尝试找到适合目标的最接近的数字。

              对于类型案例,它不会对内存做任何事情。这只是软件开发人员告诉愚蠢的编译器某个变量应该被视为不同类型的一种方式。

              我尝试在 Google 上搜索有关数字转换规则的一些信息,但周围没有多少信息。你可以试试C99 standard,但我不确定它是否会让你不知所措。 IIRC,规则是:

              • 向下转换(大类型 -> 较小的类型,如 double -> float -> int -> byte)将切断无法表示的信息(因此 double->float 将失去精度,-> int将丢失所有小数位 + 不四舍五入)。

              • 向上转换(较小的类型 -> 较大的类型)意味着用“0”填充额外的位。

              当然,也有你 can't really represent 的数字(比如 0.1)。即使没有强制转换,任何对这些的操作都会丢失信息(这就是为什么 0.1*10 可以是 != 1.0)。

              【讨论】:

                猜你喜欢
                • 2012-02-10
                • 2021-05-28
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-12-08
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多