C项目避免命名冲突


13

我正在努力寻找有关中型C库项目的函数命名约定的实用建议。我的库项目分为几个模块和带有各自标题的子模块,并且松散地遵循OO风格(所有函数均以某个结构作为第一个参数,而没有全局变量等)。它奠定了我们这样的东西:

MyLib
  - Foo
    - foo.h
    - foo_internal.h
    - some_foo_action.c
    - another_foo_action.c
    - Baz
      - baz.h
      - some_baz_action.c
  - Bar
    - bar.h
    - bar_internal.h
    - some_bar_action.c

一般来说,功能远远太大,(例如)棒some_foo_action,并another_foo_action在一个foo.c实现文件,使大多数功能静态的,收工。

在构建库时,我可以处理去除内部(“模块私有”)符号的问题,以避免用户与其客户端程序发生冲突,但是问题是如何在库中命名符号?到目前为止,我一直在做:

struct MyLibFoo;
void MyLibFooSomeAction(MyLibFoo *foo, ...);

struct MyLibBar;
void MyLibBarAnAction(MyLibBar *bar, ...);

// Submodule
struct MyLibFooBaz;
void MyLibFooBazAnotherAction(MyLibFooBaz *baz, ...);

但是,我最终得到了疯狂的长符号名(比示例长得多)。如果我没有在名称前添加“假名称空间”,则模块的内部符号名称会发生​​冲突。

注意:我不在乎骆驼案/帕斯卡案等,只是名字本身。

Answers:


10

前缀(嗯,贴上)确实是唯一的选择。您将看到的某些模式是<library>_<name>(例如OpenGL,ObjC运行时),<module/class>_<name>(例如Linux的某些部分)<library>_<module/class>_<name>(例如GTK +)。您的计划是完全合理的。

长名称如果可以预测,则不一定坏。您最终得到的疯狂的长名称和功能太大而无法在单个源文件中使用相关功能,这一事实引起了不同的关注。你有一些更具体的例子吗?


我知道您来自哪里—我想知道我对拆分成单独的文件是否过于too腐,但它对可读性,维护和git merge输入有很大帮助。作为一个例子我具有用于与OpenGL绘图UI的模块,并且我有单独的.c每个元素的文件,我需要(slider.cindicator.c等)。这些元素实现具有一个主要的绘图功能,可能长达几百行,并且内部有大量的static助手。他们还从UI模块中调用了一些纯几何函数。这听起来很典型吗?
Dan Halliday 2013年

关于长名称的一个更好的例子可能是我的音频模块-我有一个类似的层次结构Audio Module > Engines > Channels > Filters,这意味着类似MyLibAudioEngines<EngineName>Channel<ActionName>。还是在我的过滤器子模块:MyLibAudioFilters<FilterName><Type><Action>如。MyLibAudioFiltersBigSoundingCompressorFloat32Process
Dan Halliday 2013年

所有这些似乎都不合理。函数的几百行似乎有点长,但是如果您要绘制的内容很复杂,则可能很难避免。是分支繁重还是只是很多指示?
user2313838 2013年

回复:音频模块名称,您可以缩写AudioFilters / AudioEngines,因为我认为根据名称来区分它是过滤器还是模块很容易。像Float32这样的数据类型限定符也可以缩写(例如'd','f'),因为此类缩写在C编程中很常见。
user2313838

感谢您的回答-有时几乎无法获得有关C程序体系结构的良好信息(尤其是与高级语言相比)。我读过的许多C书籍都几乎没有考虑过拥有多个模块甚至一个文件的想法!总的来说,除了考虑是否为某些较长的名字使用缩写之外,我不会做太多改变。
Dan Halliday

5

C库的通常约定是使用库名作为外部可用名称的前缀,例如

struct MyLibFoo;
void MyLibAFooAction(...);

对于必须在库的多个单元中仍可访问的库内部名称,没有严格的约定,但是我将使用库名称的前缀并指出它是内部函数。例如:

struct MyLibInternalFooBaz;
void MyLibInternalFooBazAction();

我同意这会导致名称过长且难以键入,但是不幸的是,这是我们必须为没有像C ++名称空间这样的机制付出的代价。为了减少名称的长度,您需要在名称中使用缩写,但要弄清楚一些名称,但是您必须仔细权衡优缺点。


3

如果确实要避免使用长前缀,则可以缩写库名,例如Apple在iOS和OS X中的做法:

  • NSString是操作系统的NextStep根目录中的字符串
  • CALayer是一个核心动画层

2

将全局结构变量预填充函数指针怎么办?

#pragma once

typedef struct
{
    void (*doFoo)(int x);
    const char *(*doBar)(void *p);
} YourApi;

extern const YourApi yourApi;

lib.c:

#include "lib.h"

#include <stdio.h>

static void doFoo(int x)
{
    printf("Doing foo %d\n", x);
}

static const char *doBar(void *p)
{
    printf("Doing bar: %p\n", p);
    return "Hello";
}

const YourApi yourApi = {
    doFoo,
    doBar};

马具:

#include "lib.h"

int main()
{
    yourApi.doFoo(42);
    yourApi.doBar("asd");
}

静态关键字将范围限制在翻译单元内,因此不会与其他单元发生冲突。

然后,用户可以通过使用指针YourApi *ya = &yourApi,然后使用来缩短它ya->doFoo(...)

它还提供了一种模拟库以进行测试的好方法。


很酷的模式,它需要一些样板,但这将使自动完成更加有用。
里克·洛夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.