2011-08-19 9 views
14

Digamos que tengo algo como esto en un código C. Sé que puede usar un #define para hacer que el compilador no lo compile, pero solo por curiosidad le pregunto si el compilador también resolverá esto.¿El compilador optimizará esto?

Creo que esto es aún más importante para el compilador de Java, ya que no es compatible con #define.

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

} 
....... 
+13

¿Por qué no lo intentas y ves el binario resultante? –

+2

Específicamente, puede usar el comando javap -c en su clase para imprimir el bytecode, que en realidad es bastante fácil de leer. http://download.oracle.com/javase/1,5.0/docs/tooldocs/windows/javap.html – Brigham

+2

Recuerdo haber visto 'if (false) {...}' como una forma recomendada de excluir código en Java, à la '# if' en el preprocesador C. Eso fue hace varios años. – Joe

Respuesta

20

en Java, el código dentro de el if ni siquiera formará parte del código compilado. Debe compilarse, pero no se escribirá en el bytecode compilado. De hecho, depende del compilador, pero no conozco un compilador que no optimice . que las reglas se definen en the JLS:

Una optimización del compilador puede darse cuenta de que la sentencia x = 3; nunca ser ejecutado y ma y elige omitir el código para esa declaración de el archivo de clase generado, pero la instrucción x = 3; no se considera "inalcanzable" en el sentido técnico especificado aquí.

La razón de esta diferencia de trato es permitir a los programadores a definen "variables bandera", tales como:

static final boolean DEBUG = false; 

y luego escribir código como:

if (DEBUG) { x=3; } 

La idea es que se debería ser posible cambiar el valor de DEPURTO de falso a verdadero o de verdadero a falso y luego compilar el código correctamente sin ningún otro cambio en el texto del programa.

no sabe acerca de C.

+0

Enlace actualizado para Java SE 9: https://docs.oracle.com/javase/specs/jls/se9/html/jls-14.html#d5e23594 –

11

En primer lugar, Java no permite no booleana en los condicionales como C (if, while etc.). Además, si usted tiene una expresión "constante"" en sus if cheques, el compilador le advertirá de que está comparando las expresiones idénticas, así que estoy seguro de que ha optimizado a cabo. Por ejemplo

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

Este código solo genera una advertencia ("código muerto", Java 6) si 'i' no es' 1'. –

0

puedo recordar escenarios en mis programas # Java y C, donde se hicieron (optimizarlo a cabo). Pero también sé que depende mucho de la configuración del compilador - por lo tanto, el escenario es demasiado inespecífico.

En un escenario de Java, teníamos los valores const en un archivo fuente Java, mientras que se usaban en otra clase (archivo). Lo que sucedió fue que, cuando acabamos de cambiar y volver a compilar el archivo con los valores de const, nada cambiaba en el flujo de las partes en uso. Tuvimos que recompilar todo el proyecto (que es la prueba de que fue optimizado).

6

En lugar de hacer preguntas tan simples (donde la única respuesta correcta es "Pruébelo con su compilador"), ¿por qué no probarlo?

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 
} 

Usted no necesita saber mucho acerca de Java/C# código de bytes o el conjunto que ser capaz de entender lo que está pasando. Y ahora vaya y pruebe lo mismo para C# ..

0

A continuación se detalla el lenguaje C.No sé cómo lo maneja Java.

Desde int se define como un const, if (i) se convierte en una instrucción no-op aquí. Un compilador inteligente debería poder optimizar esa declaración if vacía.

Ejemplo: VC 2008

A no vacío {} con if declaración:

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 
} 
// .. 

vacío {} con if declaración:

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

que acabo de hacer una comprobación rápida con la siguiente pieza del código

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");   
     } 

    } 

} 

cuando flag = true, el tamaño de archivo de clase resultante es 708

cuando flag = false. dando como resultado el tamaño del archivo de clase es 462

lo que implica que la compilación sin duda hace la optimización de los valores static final

+0

Lo hizo con el estándar JDK 1.6 – Santosh

+1

Reproducido esto en GCC 4.4.5 (Código C) y tiene un resultado similar. – Jonathon

0

Un compilador de Java debe detectar código, obviamente, inalcanzable, que es un requisito de la lengua. Por lo que el siguiente código compila sin errores:

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); 
} 

Nota que el GMS es final, pero el compilador no se quejan de que el GMS no se ha iniciado ni se quejan de que se ha inicializado dos veces. La mayoría de los compiladores no escribirán el código muerto en el archivo de clase. Pero incluso si, el JIT lo optimizará.

C++ también tiene una noción de constantes de tiempo de compilación. A const int es una constante de tiempo de compilación, por lo que se puede usar como un argumento de plantilla sin tipo, por ejemplo. Así que cada compilador de C++ sane detectará y optimizará el código obviamente obsoleto de este tipo, incluso si compila sin especificar las opciones de optimización.

Cuestiones relacionadas