[英]C library naming conventions
大家好,我最近學會用C編程! (這對我來說是一個巨大的進步,因為C ++是第一種語言,我接觸並嚇唬了我近10年。)來自大多數OO背景(Java + C#),這是一個非常好的范式轉換。
我愛C.這是一種如此美麗的語言。 令我感到驚訝的是,高級的模塊化和代碼可重用性C支持 - 當然它不像OO語言那么高,但仍遠遠超出我對命令式語言的期望。
如何防止客戶端代碼與C庫代碼之間的命名沖突? 在Java中有包,在C#中有命名空間。 想象一下,我寫了一個C庫,它提供了“添加”操作。 客戶端很可能已經使用了類似的操作 - 我該怎么辦?
我特別想找一個客戶友好的解決方案。 例如,我不想為我的所有api操作添加前綴,例如“myuniquelibname_add”。 C世界中有哪些常見的解決方案? 你把所有api操作放在一個結構中,所以客戶端可以選擇自己的前綴嗎?
我非常期待通過你的答案得到的見解!
親愛的Answerers,謝謝你的答案! 我現在看到,前綴是安全避免命名沖突的唯一方法。 所以,我想修改我的問題: 我有什么可能,讓客戶選擇他自己的前綴?
Unwind發布的答案是單向的。 它不使用正常意義上的前綴,但必須在每個api調用前加上“api->”。 還有哪些解決方案(比如使用#define)?
這一切歸結為兩種方法之一:
我不接受任何答案,因為我認為沒有正確的答案。 選擇的解決方案取決於具體情況和自己的偏好。 我自己會嘗試你提到的所有方法,以找出最適合我的情況。 隨意在相應答案的評論中發布支持或反對某些appraoches的論據。
最后,我要特別感謝:
如果有人發現關閉這個問題是合適的(因為沒有進一步的見解),他/她應該隨意這樣做 - 我無法決定這一點,因為我不是C大師。
我不是C大師,但是從我使用的庫中,使用前綴來分隔函數是很常見的。
例如,SDL將使用SDL,OpenGL將使用gl等...
Ken提到的結構方式看起來像這樣:
struct MyCoolApi
{
int (*add)(int x, int y);
};
MyCoolApi * my_cool_api_initialize(void);
然后客戶會這樣做:
#include <stdio.h>
#include <stdlib.h>
#include "mycoolapi.h"
int main(void)
{
struct MyCoolApi *api;
if((api = my_cool_api_initialize()) != NULL)
{
int sum = api->add(3, 39);
printf("The cool API considers 3 + 39 to be %d\n", sum);
}
return EXIT_SUCCESS;
}
這仍然有“命名空間問題”; struct
name(稱為“struct tag”)必須是唯一的,並且您不能聲明自己有用的嵌套結構。 它適用於收集功能,並且是您經常在C中看到的一種技術。
更新:以下是實施方面的外觀,這是在評論中要求的:
#include "mycoolapi.h"
/* Note: This does **not** pollute the global namespace,
* since the function is static.
*/
static int add(int x, int y)
{
return x + y;
}
struct MyCoolApi * my_cool_api_initialize(void)
{
/* Since we don't need to do anything at initialize,
* just keep a const struct ready and return it.
*/
static const struct MyCoolApi the_api = {
add
};
return &the_api;
}
你被C ++嚇到了,這是一種恥辱,因為它有名稱空間來處理這個問題。 在C中,你幾乎只限於使用前綴 - 你當然不能“在一個結構中放置api操作”。
編輯:在回答關於允許用戶指定自己的前綴的第二個問題時,我會像瘟疫一樣避免它。 99.9%的用戶會對你提供的任何前綴感到滿意(假設它不是太愚蠢),並且在他們必須跳過以滿足剩余的0.1%的籃球(宏,結構,等等)時會非常不安。
作為庫用戶,您可以通過預處理器輕松定義自己的縮短命名空間; 結果看起來有點奇怪,但它有效:
#define ns(NAME) my_cool_namespace_ ## NAME
可以寫
ns(foo)(42)
代替
my_cool_namespace_foo(42)
作為圖書館作者,您可以提供此處所描述的縮寫名稱。
如果你遵循unwinds的建議並創建一個API結構,你應該使函數指針編譯時常量使inlinig成為可能,即在你的.h
文件中,使用下面的代碼:
// canonical name
extern int my_cool_api_add(int x, int y);
// API structure
struct my_cool_api
{
int (*add)(int x, int y);
};
typedef const struct my_cool_api *MyCoolApi;
// define in header to make inlining possible
static MyCoolApi my_cool_api_initialize(void)
{
static const struct my_cool_api the_api = { my_cool_api_add };
return &the_api;
}
不幸的是,沒有確定的方法可以避免C語言中的名稱沖突。由於缺少命名空間,因此您可以使用前綴全局函數和變量的名稱。 大多數圖書館選擇一些簡短且“獨特”的前綴(由於顯而易見的原因, 唯一的引號),並希望不會發生沖突。
需要注意的一點是,庫的大多數代碼都可以靜態聲明 - 這意味着它不會與其他文件中類似命名的函數沖突。 但出口功能確實必須仔細加上前綴。
由於您使用相同的名稱公開函數,因此客戶端不能包含庫頭文件以及具有名稱沖突的其他頭文件。 在這種情況下,您在函數原型之前在頭文件中添加以下內容,這也不會影響客戶端使用。
#define add myuniquelibname_add
請注意,這是一個快速解決方案,應該是最后一個選項。
有關struct方法的一個非常大的例子,請看一下Linux內核; 這種風格的30多萬行C。
前綴只是C級別的選擇。
在某些平台上(支持鏈接器的單獨命名空間,如Windows,OS X和一些商業unices,但不支持Linux和FreeBSD),您可以通過在庫中填充代碼來解決沖突,並且只從您真正需要的庫中導出符號。 (例如,如果導出符號中存在沖突,則在importlib中出現別名)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.