簡體   English   中英

C庫命名約定

[英]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)?

編輯2(狀態更新)

這一切歸結為兩種方法之一:

  • 使用結構
  • 使用#define(注意:有很多方法,如何使用#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM