编译器会优化它吗?

时间:2011-08-19 14:02:26

标签: java c optimization

说我在C代码中有这样的东西。我知道你可以使用#define代替,让编译器不能编译它,但出于好奇,我问的是编译器是否也会解决这个问题。

我认为这对Java编译器来说更为重要,因为它不支持#define

const int CONDITION = 0;
........
// Will the compiler compile this?
if ( CONDITION )
{

}
.......

7 个答案:

答案 0 :(得分:21)

在Java中,if中的代码甚至不会是编译代码的一部分。它必须编译,但不会写入编译的字节码。它实际上取决于编译器,但我不知道没有优化它的编译器。规则在the JLS中定义:

  

优化编译器可以实现语句x = 3;永不   执行并可以选择省略该语句的代码   生成的类文件,但语句x = 3;不被视为   在这里指定的技术意义上“无法到达”。

     

这种不同处理的理由是允许程序员   定义“标志变量”,例如:

static final boolean DEBUG = false;
     

然后编写如下代码:

if (DEBUG) { x=3; }
     

这个想法是应该可以改变DEBUG的值   从false到true或从true到false然后编译代码   正确,没有对程序文本进行其他更改。

不知道C。

答案 1 :(得分:11)

首先,Java不允许在C(ifwhile等条件句中使用非布尔值。另外,如果你的if检查中有一个“常量”表达式,编译器会警告你正在比较相同的表达式,所以我确定它已经过优化。例如。

    final int i = 1;
    if (1 == i) { // warning
        System.out.println("HI");
    }

答案 2 :(得分:6)

而不是问这么简单的问题(唯一正确的答案是“用你的编译器试试”) - 为什么不尝试呢?

public class Test {
    public static void main(String[] args) {
        if (true) {
            System.out.println("Yep");
        }
        boolean var = false;
        if (var) {
            System.out.println("Nope");
        }
        final boolean var2 = false;
        if (var2) {
            System.out.println("Nope");
        }
    }
}

javac .\Test.java 
javap -c Test
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String Yep
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: iconst_0
       9: istore_1
      10: iload_1
      11: ifeq          22
      14: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      17: ldc           #3                  // String Yep
      19: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      22: return
}

您无需了解java / c#字节码或汇编就能了解正在发生的事情。现在去尝试C#..

答案 3 :(得分:2)

我刚刚使用以下代码进行了快速检查

public class Test {
    private static final boolean flag = true;

    public static void main(String[] args) throws InterruptedException {

        if(flag){
            System.out.println("1");
            System.out.println("1");
            System.out.println("1");
            System.out.println("1");
            System.out.println("1");
            System.out.println("1");
            System.out.println("1");
            System.out.println("1");
            System.out.println("1");        
        }

    }

}

当flag = true时,生成的类文件大小为708

当flag = false时。结果类文件大小为462

这意味着编译肯定会对静态最终值进行优化

答案 4 :(得分:0)

我可以回想一下我的Java和C#程序中的场景,它在哪里(优化它)。但我也知道这很大程度上取决于编译器设置 - 因此场景太不明确了。

在Java场景中,我们在一个Java源文件中使用了const值,而在另一个类(文件)中使用了它们。发生的事情是,当我们刚刚更改并使用const值重新编译文件时,使用部件的流程没有任何变化。我们不得不重新编译整个项目(这是它被优化的证据)。

答案 5 :(得分:0)

以下是 C 语言的具体内容。我不知道 Java 如何处理它。

由于int被定义为const,因此if (i)成为no-op指令。智能编译器应该能够优化掉那个空if语句。

示例:VC 2008

带有{}声明的非空if

const int i = 1;
// mov dword ptr [i], 1
if (i)
// mov eax, 1
// test eax, eax
// je wmain+35h
{
   int j = 2;
   // move dword ptr [j], 2
}
// ..

使用{}声明清空if

const int i = 1;
// mov dword ptr [i], 1
if (i)
{
}
// ..

答案 6 :(得分:0)

java编译器必须检测明显无法访问的代码,这是语言要求。所以下面的代码将编译没有错误:

static final boolean flag = true; 

public static void main(String[] args) {
    final String msg;
    if (flag)
        msg = "true";
    if (!flag)
        msg = "false";
    System.out.println(msg);
}

请注意,msg是最终的,但编译器既没有抱怨msg没有初始化也没有抱怨它被初始化两次。大多数编译器都不会将死代码写入类文件。但即便如此,JIT也会对其进行优化。

C ++也有编译时常量的概念。 const int是一个编译时常量,因此它可以用作非类型模板参数。因此,即使您在没有指定优化选项的情况下进行编译,每个理智的C ++编译器都会检测并优化掉这种类型的死代码。