API Name Postfix
來聊聊 API 命名時,後綴字的處理。
版號後綴字
Windows SDK API 裡有個奇怪的命名慣例 (naming convention),學過 Windows Programming 應該都耳熟能詳:API 的加強版,通常是在原來的名字後面,加上個 Ex 後綴字尾以命名之。例如,CreateWindow() 的加強版,就叫做 CreateWindowEx()。
之所以說這種命名慣例會「奇怪」是因為,如果還要對 Ex 版增強的時候,該怎麼辦?難道還要來一個 CreateWindowExEx() 嗎?那豈不沒完沒了?
針對這種問題,常見的解法有兩種。第一種比較簡單,就是棄 Ex 改數字。例如 sqlite3_open() 與 sqlite3_open_v2() 和 xmlrpc_client_init() 與 xmlrpc_client_init2()。SQLite 的命名法比較囉唆,可是應該是因為還要支援 UTF-16 版的緣故;xmlrpc-c 的方法比較常見,個人認為也比較簡潔方便。
型別後綴字
除了利用後綴字來表明版號之外,有時候,函式名稱後綴字也用來表明,其所處理的資料型別。舉例來說,Microsoft 的 generic-text-mapping 技術,利用 A 或 W 後綴,來區分輸出入使用 char 或 wchar_t 型別。
前述提到 sqlite3_open() 有 UTF-16 版本,命名為 sqlite3_open16(),也是類似的手法。
我個人覺得,這種後綴字還算可以接受,可是如果是在用 C++,那就很搞笑了。事實上,若有機會用 C++ 把這類 C 的 API 包裝起來的話,我都會利用 overloading 機制,把型別後綴字幹掉,圖個清爽。
行為後綴字
另一種常見的 API 後綴字,代表著函式的行為不太一樣。例如很多 non-thread-safe 的 API,其 reentrant 版,也就是可安全地重複使用的版本[1],會在名稱後面加上 _r 的後綴字。例如 strtok() 的 reentrant 版叫 strtok_r()。通常加上 _r 的 API,其參數都會不太一樣,否則直接解掉問題即可,沒必要再另外發明一個 API。
Microsoft 在 Visual C++ 裡,對這類 non-thread-safe 的 API,解法不太一樣。使用 multithread 版 run-time library 時,若要從 non-thread-safe 變成 thread-safe 時,參數可以一樣不變,則同上述直接改掉實作,解掉問題,API 不變。可是,當碰到需要修改 prototype 更動參數時,Microsoft 用的是骯髒的手段,如利用 TLS 儲存需要增加的參數,使得 API 還是不變[2]。原本因呼叫了 non-thread-safe API 的程式,立地成佛變成 thread-safe。
這其實會產生一些問題,妨礙 porting 我認為問題還小,讓 programmer 自以為安全,才是真正的隱憂。我認為,Microsoft 應該要做的,其實是當使用 multithread 版 run-time library 時,像 security enhanced crt 那樣,在 compile 時產生 deprecation warning,建議使用 reentrant 版 API 才對。
講到 VC 的 security enhanced crt 就好笑,Microsoft 會在有安全疑慮的 API 後面,加上個 _s 後綴字。但問題是,M$ 根本沒有在管,參數是否相同,只要有安全疑慮,即使參數相同,也會發明一個對應的 _s 版 API。若目的是為了讓 programmer 可以認知道其實這個 API 並不安全,那就很搞笑了,參數相同時,讓 API 實作能夠安全,不正是 vendor 的責任嗎?更別提,實際上 _s 版 API,並沒有多安全的問題了。
隨便亂選後綴字
講了這麼多,其實我是想碎碎念,新同事你實作 thread-safe 版 API,在後面加上 _s 後綴字是想怎樣?畫虎不成反類犬,真是厲害。
還好我不再需要面對這種隨便亂選後綴字的 API 了。阿彌陀佛,善哉,善哉。



One Comment
1. 那個 _s 的版本連他們自己都不一定在用,像你只要使用 std::copy() 就會丟出一堆 warning 跟你講說請改用 _s 的版本,因為他們的 std::copy() 的實做都是用沒有 _s 的 API.
2. TLS 實在是個逃避問題的工具,並沒有解決問題。最近發現 Boost.thread 也用到 TLS,而且在 1.37.0 之前的版本只有 TLSAlloc() 而沒有 call TLSFree(),會造成 leak。而 1.37.0 開始的版本雖然沒 leak 了,但只要 static link 到某個有使用到 mfc 的 DLL 就會產生 link error。到相關的 mail list 問了,短期內無解 >_<.
最後我只好把有用到的幾個 Boost.thread 工具全都自己寫一遍。
Post a Comment