2010-06-13 66 views
2

以下兩種方法之一在另一種方法中是否有優勢?C變量聲明和錯誤處理優先級的最佳實踐

這是第一次測試,fopen是否成功都和然後所有的變量聲明發生,以確保它們不會進行,因爲它們不能不得不

void func(void) { 
    FILE *fd; 

    if ((fd = fopen("blafoo", "+r")) == NULL) { 
      fprintf(stderr, "fopen() failed\n"); 
      exit(EXIT_FAILURE); 
    } 

    int a, b, c; 
    float d, e, f; 
    /* variable declarations */ 

    /* remaining code */ 
} 

這恰恰相反。所有的變量聲明發生,即使fopen失敗

void func(void) { 
    FILE *fd; 
    int a, b, c; 
    float d, e, f; 
    /* variable declarations */ 

    if ((fd = fopen("blafoo", "+r")) == NULL) { 
      fprintf(stderr, "fopen() failed\n"); 
      exit(EXIT_FAILURE); 
    } 

    /* remaining code */   
} 

沒有第二種方法產生任何額外費用,當fopen失敗? 很想聽聽你的想法!

+1

爲什麼要優化exit(EXIT_FAILURE)分支的路徑?你期望它發生很多? – u0b34a0f6ae 2010-06-13 11:53:47

+1

這只是一個例子來指代一個更一般的結構。 – guest 2010-06-13 11:54:47

+0

[如何處理條件初始化,這是一個很好的做法?](http://stackoverflow.com/questions/16102683/how-is-conditional-initialization-handled-and-is-it-a-good -ractract) – tne 2014-02-23 16:37:57

回答

4

不,它沒有任何費用。這兩個例子最可能編譯成相同的結果二進制文件。因爲變量聲明沒有賦值實際上並不實際 C中的任何東西,它不會生成任何代碼。這些變量可用的空間將在需要時由堆棧指針簡單地跳過。

1

fopen失敗時,應用程序退出,所以沒有人真正關心變量是否已初始化。沒有成本,因爲應用程序已經終止,並且靜態分配的內存已經釋放。如上所述,內存甚至沒有被分配,但是如果你將它們全部設置爲默認值,比如0,那麼將會有內存。即使你改變了這種行爲,也沒有額外的成本。

此外,第二個代碼可能是可取的,因爲它符合C89。

+0

所以它不佔用任何額外的時間,對於已經被初始化爲空的變量? – guest 2010-06-13 11:50:44

+0

變量初始化適用於編譯器,而不是二進制。 – alternative 2010-06-13 11:51:37

+0

當然,迭代數組需要時間,但是在聲明變量的地方,不管它們有多「大」,都沒有區別。 – 2010-06-13 12:00:12

1

在這兩種情況下,在函數的頂部可能會發生同一範圍內函數中所有變量的堆棧變量分配,所以任何一種方法都可以。

0

它應該沒有什麼區別,但是您可以隨時比較兩個版本的組件輸出以確保!

堆棧上的空間總是在函數入口處準備好,可能是爲了獲得一個很好的函數將變量名映射到編譯器/編譯器編寫器的基本指針+偏移量。至於初始化,它也不應該有任何區別。內容是未定義的,直到在兩個版本中寫入變量爲止。然而,在C++中,當跳過初始化(在你的例子中你沒有做的代碼)時,你可能會遇到一些問題,但是C++的理由要複雜得多。

1

你的例子中的變量聲明在大多數編譯器中不會增加額外的開銷。他們唯一可能的時候是如果他們有初始化值需要任何非平凡的代碼產生。

例如:

void func(const char * filename) { 
    FILE *fd; 
    int a, b, c; 
    size_t z = strlen(filename); 
    float d, e, f; 
    /* variable declarations */ 

    if ((fd = fopen(filename, "+r")) == NULL) { 
      fprintf(stderr, "fopen() failed\n"); 
      exit(EXIT_FAILURE); 
    } 

    /* remaining code */  
    /* Some code that uses z */ 
} 

在這個例子中strlen可以嘗試打開文件之前被調用,但它從來沒有使用的價值。在fopen之後撥打電話strlen可能會產生更好的代碼。但這不是最好的例子,因爲編譯器經常知道像strlen這樣的幾個函數是純粹的函數(沒有副作用,只能用它們的參數來產生結果),並且可以將調用移動到以下的strlen,但是您應該明白了。