2013-05-09 57 views
3

C89 海合會(GCC)4.7.2在函數返回一個靜態結構

你好,

我保持某人的軟件,我發現這個函數返回一個靜態結構的地址。這應該是好的,因爲靜態會指示它是全局的,所以結構的地址在程序終止之前可用。

DRIVER_API(driver_t*) driver_instance_get(void) 
{ 
    static struct tag_driver driver = { 
    /* Elements initialized here */ 
    }; 

    return &driver; 
} 

像這樣來使用:

driver_t *driver = NULL; 
driver = driver_instance_get(); 

驅動變量是整個程序中使用,直到其終止。

一些問題:

  1. 它是很好的做法,以做到這樣嗎?
  2. 是否有任何區別,聲明它在文件級功能之外是靜態的?
  3. 爲什麼不傳遞一個內存池到函數中,並將內存分配給結構,以便在堆中聲明結構?

非常感謝您的任何建議,

+0

這個結構特別大,你會非常關心它的出口? – 2013-05-09 14:48:30

+0

如果結構是隻讀的,那麼函數可能應該返回一個指向「const」結構的指針。另外,什麼是'DRIVER_API'? – 2013-05-09 14:56:40

+0

DRIVR_API是#define DRIVER_API(類型)EXTERN_C __declspec(dllexport)類型 – ant2009 2013-05-09 15:45:24

回答

3
  1. 一般來說,沒有。它使該功能不可重入。在代碼作者真正知道他們在做什麼的情況下,它可以用於剋制。

  2. 在外面聲明它會污染文件級名稱空間和結構對象的名稱。由於在其他地方不需要直接訪問該對象,所以在函數中聲明它更合理。沒有其他區別。

  3. 分配在堆上?性能會受損。內存碎片會發生。調用者將承擔明確釋放內存的任務。強制用戶在可以避免時使用動態內存通常不是一種好的做法。

    可重用實現的一個更好的想法是將指針從外部傳遞到目標結構。這樣調用者就可以以任何他們認爲合適的方式自由分配接收者的內存。


當然,你所看到的在這裏可以簡單地是一個C實現單例類的成語(最有可能的是,通過該功能的名稱判斷)。這意味着該函數應該每次都返回相同的指針,即所有的調用者都應該通過返回的指針來查看和共享同一個結構對象。而且,可能的話,你甚至可能會期望修改同一個對象(假設沒有併發)。在這種情況下,您在這裏看到的是全局變量的函數包裝實現。所以,在這種情況下改變任何東西實際上都會挫敗目的。

+0

1. ... like *只讀* struct/pointer – 2013-05-09 14:52:10

3
  1. 只要你意識到其對由該函數返回的指針的任何代碼修改同一個變量爲得到相同的指針指的是任何其他代碼,它是不是一個巨大的問題。只要'可以是一個相當重要的問題,但它是有效的。它通常不是最佳實踐 - 例如,返回指向單個靜態變量的指針的C函數(如asctime())並不像將結果放入用戶提供的變量那樣容易使用 - 尤其是在線程代碼中(該功能不可重入)。然而,在這種情況下,它看起來像你正在實現一個Singleton模式;你可能只需要一個'驅動程序'的副本,所以對我來說看起來很合理 - 但是在指出'這是惡魔般的錯誤'之前,我們需要更多關於用例的信息。

  2. 這裏的函數static和文件靜態變量之間並沒有太大的區別。區別在於實現代碼(文件中的靜態變量可以被文件中的任何代碼訪問;函數靜態變量只能在一個函數中訪問),而不是用戶代碼中。

  3. '內存池'不是一個標準的C概念。一般來說,通過被調用函數初始化結構可能會更好,但它取決於上下文。就目前而言,爲了它的目的而設計,這是可以的。

注:該代碼將被更好地寫成:

driver_t *driver = driver_instance_get(); 

優化器將可能無論如何優化代碼,這一點,但沒有點分配NULL,然後立即重新分配。