命名の競合を回避する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_actionanother_foo_action、1つのfoo.c実装ファイルに入れて、ほとんどの関数を静的にして、1日で呼び出します。

ユーザーのクライアントプログラムとの競合を避けるために、ライブラリを構築するときに内部(「モジュールプライベート」)シンボルを削除することもできますが、問題はライブラリ内のシンボルの名前の付け方ですか?これまで私はやってきた:

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

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

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

しかし、私は(例よりはるかに長い)クレイジーな長いシンボル名になってしまいました。名前の前に「偽の名前空間」を付けない場合、モジュールの内部シンボル名はすべて衝突します。

注:キャメルケース/パスカルのケースなどは気にせず、名前だけを気にします。

回答:


10

プレフィックス(まあ、添付)が本当に唯一のオプションです。表示されるパターンは次のとおりです<library>_<name>、OpenGL、ObjCランタイムなど、<module/class>_<name>Linuxの一部など<library>_<module/class>_<name>、GTK +などがあります。あなたのスキームは完全に合理的です。

長い名前は、予測可能であれば必ずしも悪いわけではありません。単一のソースファイル内の関連する関数に固執するには大きすぎるクレイジーな長い名前と関数で終わるという事実は、さまざまな懸念を引き起こします。もっと具体的な例はありますか?


私はあなたがどこから来たのかを知っています—私は別々のファイルに分割することにあまりにも精通しているのではないかと思っていますが、それは読みやすさ、メンテナンス、git mergeingに大いに役立ちます。例として、OpenGLでUIを描画するためのモジュールが.cありslider.c、必要な要素ごとに個別のファイルがあります(indicator.cなど)。これらの要素実装には、おそらく数百行のメイン描画機能と、かなりの数のstaticヘルパーが含まれています。また、UIモジュール内からいくつかの純粋なジオメトリ関数を呼び出します。それはかなり典型的な音ですか?
ダン・ハリディ

長い名前のよりよい例は私のオーディオモジュールであるかもしれない-私は次のように階層持っているAudio Module > Engines > Channels > Filtersようなものを意味しますMyLibAudioEngines<EngineName>Channel<ActionName>。または私のフィルターサブモジュールで:MyLibAudioFilters<FilterName><Type><Action>例えば。MyLibAudioFiltersBigSoundingCompressorFloat32Process
ダン・ハリディ

それのどれも不合理に思えません。関数の数百行は少し長いように見えますが、描画しているものが複雑な場合、それを避けるのは困難です。それはブランチが重いですか、それとも単に大量の命令ですか?
user2313838

再:オーディオモジュールの名前は、AudioFilters / AudioEnginesと略すことができます。名前に基づいたフィルターまたはモジュールであるかどうかは簡単にわかると思います。Float32のようなデータ型修飾子も省略できます(例: 'd'、 'f')。このような省略形はCプログラミングでは一般的です。
user2313838

ご回答ありがとうございます。Cプログラムアーキテクチャに関する優れた情報を得ることが不可能に近い場合があります(特に高レベルの言語と比較して)。私が読んだ多くのCの本は、複数のモジュールまたは複数のファイルを持つという考えをほとんど考慮していません!全体として、一部の長い名前の略語を使用するかどうかを考慮する以外は、あまり変更しないと思います。
ダン・ハリディ

5

Cライブラリの通常の規則は、外部で使用可能な名前のプレフィックスとしてライブラリ名を使用することです。

struct MyLibFoo;
void MyLibAFooAction(...);

ライブラリの複数のユニットで引き続きアクセス可能でなければならないライブラリ内部名の場合、厳密な規則はありませんが、ライブラリ名のプレフィックスと、それが内部関数であることを示します。例えば:

struct MyLibInternalFooBaz;
void MyLibInternalFooBazAction();

これは非常に長く入力しにくい名前につながる可能性があることに同意しますが、残念なことに、C ++名前空間のようなメカニズムを持たないために支払わなければならない代償です。名前の長さを短くするには、多少の明瞭さを犠牲にして、名前に略語を使用することを選択できますが、長所と短所を慎重に検討する必要があります。


3

長い接頭辞を避けたい場合は、AppleがiOSおよびOS Xで行うように、ライブラリ名を短縮できます。

  • NSStringは、OSのNextStepルートからの文字列です
  • CALayerはコアアニメーションレイヤーです

2

グローバル構造変数に関数ポインターが事前に入力されているとどうなりますか?

lib.h

#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");
}

staticキーワードは、スコープが翻訳単位に制限されるため、他のユニットと衝突しません。

ユーザーは、のようなポインターを使用してそれを短縮しYourApi *ya = &yourApi、次にya->doFoo(...)

また、ライブラリをテスト用にモックする優れた方法も提供します。


クールなパターンです。ボイラープレートが少し必要ですが、これによりオートコンプリートがはるかに便利になります。
リック・ラブ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.