2012-06-06 101 views
13

我知道斷言可以分別在運行時啓用/禁用,用於調試和生產。然而,我發現斷言也增加了生成的二進制文件的大小(在下面的例子中大約爲100-200字節)。無斷言編譯

在C和C++中,我們可以在編譯時通過#define NDEBUG#include <assert.h>之前執行此操作。

有什麼辦法讓Java編譯器自動做到這一點?我想將它們保留在源代碼中以便稍後進行調試。但我也不希望得到的二進制文件比任何大於必要的大小(我們有一個大小限制作爲設計要求)。

C代碼:

//#define NDEBUG 
#include <assert.h> 

int main(void) { 
    assert(0); // +200 bytes without NDEBUG, 0 with NDEBUG 
    return 0; 
} 

Java代碼:

public class Test { 
    public static void main(String[] args) { 
     assert(System.nanoTime()==0); // increases binary size by about 200 bytes 
    } 
} 

針對國陣的答案:

public class Test2 { 
    public static final boolean assertions = false; 

    public static void main(String[] args) { 
     if(assertions) { 
      assert(System.nanoTime()==0); 
     } 
    } 
} 

編輯:事實上,它似乎對我來說,這個啓用/禁用是一個更有用的編譯時間e功能比運行時。我的意思是,有多少終端用戶可以啓用它們?就調試過程中的程序員而言,他/她可能會重新編譯代碼。

+0

這並不能證明每個斷言的開銷都是200字節,只有那個。 – EJP

+1

@EJP:當然。我的意思是說整體聲明導致的不可忽略的增長。確切數額當然取決於聲明的複雜性。 – tskuzzy

+1

如果你打擾這些事情,你的語言是錯誤的。 – lvella

回答

2

我個人不能執行以下操作,因爲複雜的添加到源代碼,但javac的生成main在以下兩個片段完全相同的中間代碼:

條件斷言

class C { 
    public final static boolean assertions = false; 

    public static void main(String[] args) { 
     if(assertions) { 
      assert(System.nanoTime()==0); 
     } 
    } 
} 

no asserts

class C { 
    public static void main(String[] args) { 
    } 
} 

編譯代碼

public static void main(java.lang.String[]); 
    Code: 
     0: return   
    LineNumberTable: 
     line 3: 0 

編輯

事實上,在我看來,這種啓用/禁用比運行時更爲有用 編譯時的功能。我的意思是,有多少最終用戶將 啓用它們?

它不是最終用戶,而是啓用它們的最終用戶,它是告知最終用戶啓用它們的客戶支持。我希望雖然它們已被啓用,但未被禁用,默認情況下。

+0

非常感謝!我同意這不是一個非常優雅的解決方案,但它確實解決了我的問題。 – tskuzzy

+0

看來,如果你在一個分離的類上放置你的'public final static boolean assertions = false;'變量,這樣你就可以在你的代碼中使用斷言,只需在一個地方更改標誌,就需要重新編譯整個如果它改變了(這是可取的,因爲你想從你的編譯代碼中擦掉變量)。 – lvella

+0

@Ivella這是因爲編譯器內聯公共靜態決賽。 –

4

這不可能作爲內置的編譯步驟。然而,你可以通過在你的斷言中添加條件塊來做到這一點。

有關更多信息,請參閱文章"Removing all Trace of Assertions from Class Files"

+0

聽起來像一個好主意,但它實際上增加了另外50個字節的二進制。 – tskuzzy

+0

這沒什麼意義,因爲編譯器應該完全刪除這些語句,因爲它現在無法訪問。 – Robin

+2

@Robin如果OP使用'final',它會減小大小。 –