我正在制作一個需要初始化才能正常作業的低級庫,我用 init 函式實作了它。我想知道是否有辦法在用戶理想情況下呼叫庫函式時呼叫 init 呼叫,而無需:
- 任何開銷
- 無重復來電
- 沒有暴露的全域變數。(我目前的解決方案是這樣做的,我不太喜歡)
根據評論請求,我當前的解決方案:
bool isinit = 0;
void init()
{
isinit = 1;
// init code
}
void lib_function()
{
if(!isinit) init();
// function code
}
編譯器似乎足夠聰明(在 gcc 上使用 -0fast)不會在每次呼叫 lib_function 時進行比較,但這仍然暴露了一個我不喜歡的全域變數。
uj5u.com熱心網友回復:
抽象出 init 函式的最佳方法?
當然你的圖書館有一些狀態。通常,庫公開在特定結構上作業的函式。不要使用全域變數 - 不要撰寫意大利面條式代碼。公開保存庫狀態的結構,并使庫的所有函式都將指向該結構的指標作為引數。使用命名空間 - 在所有匯出的符號前加上前綴。init 函式就像int lib_init(struct lib_the_struct *t);- 用戶需要在使用前使用該函式初始化結構是不言而喻的。例如:fopen(),pthread_create。
在您的庫中撰寫一個 init 函式。撰寫清晰的檔案說明,您的庫的用戶必須在呼叫任何其他函式之前呼叫該函式一次。例如:https : //curl.se/libcurl/c/curl_global_init.html。
uj5u.com熱心網友回復:
如果您對作為通用擴展而不是 C 標準一部分的解決方案感到滿意,您可以使用建構式屬性標記您的 init 函式,以確保在程式初始化期間(或在共享庫加載期間,如果您最終使用那個)。
uj5u.com熱心網友回復:
我會用斷言來解決這個問題,這樣 if 就會在發布版本中消失,如果你忘記在某個地方呼叫 init_function ,你會在開發時遇到錯誤。
還將 isinit 轉換為靜態,以便每個庫都可以擁有自己的同名變數。
#include <assert.h>
#ifndef NDEBUG
static int isinit = 0;
#endif
void lib_function()
{
assert(isinit && "library: init not called");
}
uj5u.com熱心網友回復:
這里將是開銷,如果你運行if(!isinit) init();在每次呼叫一個函式的時間。至少有一個額外的分支。
至于洗掉全域變數,請在您的示例中執行但static bool isinit = 0;. 這將變數的范圍縮小到本地翻譯單元(.c 檔案和它包含的所有 .h 檔案)。它不再是“全球性的”。請注意,這在多執行緒場景中并不理想 - 然后您必須使用互斥鎖保護變數。
總的來說,您嘗試做的并不是一個好主意。C 庫有一個 init 函式是很常見的約定,庫的用戶應該在呼叫其他任何東西之前呼叫它,否則他們應該受到指責,而不是你的庫。當然,您必須通過源代碼檔案向他們說明這一點。源代碼注釋中的先決條件串列以及放置在庫頭檔案中的每個函式宣告是很常見的。
uj5u.com熱心網友回復:
雖然函式默認匯出,但變數不是。所以變數不是全域的/公開的。只有您的圖書館可以看到它。
#include <stdbool.h>
int main(void) {
bool b = isinit;
}
$ gcc -Wall -Wextra -pedantic lib.c main.c -o a
main.c: In function ‘main’:
main.c:4:13: error: ‘isinit’ undeclared (first use in this function); did you mean ‘int’?
bool b = isinit;
^~~~~~
int
main.c:4:13: note: each undeclared identifier is reported only once for each function it appears in
main.c:4:9: warning: unused variable ‘b’ [-Wunused-variable]
bool b = isinit;
^
因此,您無需更改任何內容即可實作您想要的效果。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/379845.html
標籤:C
上一篇:如何將字串轉換為double?
下一篇:函式做一個盡可能多的操作
