C库命名约定

Dav*_* O. 16 c 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大师.

pht*_*ier 16

我不是C大师,但是从我使用的库中,使用前缀来分隔函数是很常见的.

例如,SDL将使用SDL,OpenGL将使用gl等...


unw*_*ind 10

Ken提到的结构方式看起来像这样:

struct MyCoolApi
{
  int (*add)(int x, int y);
};

MyCoolApi * my_cool_api_initialize(void);
Run Code Online (Sandbox Code Playgroud)

然后客户会这样做:

#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;
}
Run Code Online (Sandbox Code Playgroud)

这仍然有"命名空间问题"; 该struct名称(称为"结构标签")必须是唯一的,而不能声明嵌套结构,通过本身是有用的.它适用于收集功能,并且是您经常在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;
}
Run Code Online (Sandbox Code Playgroud)


小智 6

你被C++吓到了,这是一种耻辱,因为它有名称空间来处理这个问题.在C中,你几乎只限于使用前缀 - 你当然不能"在一个结构中放置api操作".

编辑:在回答关于允许用户指定自己的前缀的第二个问题时,我会像瘟疫一样避免它.99.9%的用户会对你提供的任何前缀感到满意(假设它不是太愚蠢),并且在他们必须跳过以满足剩余的0.1%的篮球(宏,结构,等等)时会非常不安.

  • 为什么如此使用struct作为命名空间呢?只需创建一个函数指针结构,它看起来与静态类方法非常相似.这打败了一堆优化,但也为您提供了更多控制,并打开了有趣的状态管理选项. (3认同)
  • 既然你提到了 SQLite,我认为有必要指出 SQLite _确实是这样做的!http://www.sqlite.org/c3ref/io_methods.html 和 http://www.sqlite.org/c3ref/vfs.html (2认同)

Chr*_*oph 5

作为库用户,您可以通过预处理器轻松定义自己的缩短名称空间;结果看起来有点奇怪,但它有效:

#define ns(NAME) my_cool_namespace_ ## NAME
Run Code Online (Sandbox Code Playgroud)

使得可以写

ns(foo)(42)
Run Code Online (Sandbox Code Playgroud)

代替

my_cool_namespace_foo(42)
Run Code Online (Sandbox Code Playgroud)

作为库作者,您可以提供此处所述的缩写名称。

如果您遵循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;
}
Run Code Online (Sandbox Code Playgroud)

  • @ijustlovemath:因为变量具有静态存储持续时间 (2认同)