Ternary和If/Else是否可以编译成相同的东西,为什么呢? [英] Do Ternary and If/Else compile to the same thing, why?

查看:52
本文介绍了Ternary和If/Else是否可以编译成相同的东西,为什么呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编译器是否将简单的三元语句编译为与编译简单的if语句相同的东西?另外,为什么要设计一个编译器来以不同的方式编译它们?

Do compilers compile a simple ternary statement to the same thing that they would compile a simple if else statement? Also, why would a compiler be designed to compile them differently?

例如,会这样:

int a = 169;
int b = 420;
int c;
c = a > b ? 42:69;

编译成与此相同的东西:

compile to the same thing as this:

int a = 169;
int b = 420;
int c;
if(a>b) c = 42;
else c = 69;

这个问题不是关于哪个更好,何时使用每个问题,因此请不要在回答中包括它.

This question is not about which is better or when to use each one, so please don't include that in your answer.

推荐答案

首先,这与实现有关.只要字节码在支持Java虚拟机规范的VM上运行时,字节码满足Java语言规范,JLS便没有确切规定必须如何编译特定的代码片段或操作.只要在兼容的JVM上运行时产生相同的结果,则不同的编译器可以生成与给定示例不同的字节码.

First of all, this is implementation-dependent. The JLS does not specify exactly how a specific snippet or operation must be compiled, as long as the bytecode satistifes the Java Language Specification when run on a VM supporting the Java Virtual Machine specification. A different compiler can generate bytecode that is different from the examples given, as long as it gives the same result when run on a compliant JVM.

在Java 8的 javac (1.8.0_65)上,条件运算符和if-else的代码不同.

On Java 8's javac (1.8.0_65), the code is not the same for the conditional operator, and the if-else.

三元运算符控制将哪个值压入堆栈,然后无条件存储堆栈顶部的值.在这种情况下,如果 a> b ,则推送42,代码跳至 istore ,否则,推送59.然后,将最上面的任何值 istore 转换为 c .

The ternary operator controls which value is pushed to the stack, and then the value on the top of the stack is stored unconditionally. In this case, if a>b, 42 is pushed and code jumps to the istore, else 59 is pushed. Then whatever value is on top is istored to c.

在if-else中,条件控制实际调用哪个 istore 指令.

In the if-else, the conditional controls which istore instruction is actually called.

但是请注意,在这两种情况下,指令都是"compare小于或等于",它会跳转到else分支(否则继续if分支).

Notice however that in both cases the instruction is "compare less than or equal" which jumps to the else branch (continuing the if branch otherwise).

下面可以看到各种编译器生成的字节码.您可以使用OpenJDK JDK中提供的 javap 工具自己获得它(示例命令行 javap -c ClassName )

Below can be seen the bytecode generated by various compilers. You can get it yourself using the javap tool available in an OpenJDK JDK (example command-line javap -c ClassName)

具有三进制的javac:

javac with ternary:

  public static void main(java.lang.String...);
    Code:
       0: sipush        169
       3: istore_1
       4: sipush        420
       7: istore_2
       8: iload_1
       9: iload_2
      10: if_icmple     18
      13: bipush        42
      15: goto          20
      18: bipush        69
      20: istore_3
      21: return

带有if-else的javac:

javac with if-else:

  public static void main(java.lang.String...);
    Code:
       0: sipush        169
       3: istore_1
       4: sipush        420
       7: istore_2
       8: iload_1
       9: iload_2
      10: if_icmple     19
      13: bipush        42
      15: istore_3
      16: goto          22
      19: bipush        69
      21: istore_3
      22: return
}

但是,使用 ecj 时,代码更加奇怪.三元运算符有条件地推送一个或另一个值,然后将其弹出以丢弃它(不存储):

However, with ecj, the code is even more odd. Ternary operator conditionally pushes one or the other value, then pops it to discard it (without storing):

Code:
   0: sipush        169
   3: istore_1
   4: sipush        420
   7: istore_2
   8: iload_1
   9: iload_2
  10: if_icmple     18
  13: bipush        42
  15: goto          20
  18: bipush        69
  20: pop
  21: return

ecj 和if-else可以优化推送/存储,但是仍然包括一个奇数比较(请注意,比较没有副作用,需要保留):

ecj with if-else somehow optimizes out the pushes/stores but still includes an oddball comparison (mind you, there are no side effects to the comparison that need to be retained):

Code:
   0: sipush        169
   3: istore_1
   4: sipush        420
   7: istore_2
   8: iload_1
   9: iload_2
  10: if_icmple     13
  13: return

当我添加一个 System.out.println(c)来阻止这种未使用的值丢弃时,我发现这两个语句的结构与 javac (三元进行条件推送和固定存储,而if-else进行条件存储)​​.

When I add a System.out.println(c) to foil this unused-value discard, I find that the structure of both statements is similar to that of javac (ternary does conditional push and fixed store, while if-else does conditional store).

这篇关于Ternary和If/Else是否可以编译成相同的东西,为什么呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆