web-dev-qa-db-ja.com

Cで複雑なプロジェクトをどのように構成する必要がありますか?

私には初心者レベルのCスキルしかありません。Cでやや複雑なアプリケーションを構築するための事実上の「標準」があるかどうかを知りたいです。GUIベースのアプリケーションですら。

私はいつもOOパラダイムJava and PHPそして今私はCを学びたいと思っているアプリケーションを間違った方法で構成することを恐れて、手続き型言語でモジュール性、分離、乾燥を実現するためにどのガイドラインに従うべきか迷っています。

提案する読み物はありますか? Cのアプリケーションフレームワークを見つけることができませんでした。フレームワークを使用していなくても、コードを参照することで常に良いアイデアを見つけました。

78
Josh

キーはモジュール性です。これは、設計、実装、コンパイル、および保守が簡単です。

  • OOアプリのクラスのように、アプリのモジュールを識別します。
  • 各モジュールのインターフェイスと実装を分離し、他のモジュールに必要なものだけをインターフェイスに配置します。 Cには名前空間がないため、インターフェイスのすべてを一意にする必要があります(たとえば、プレフィックスを付ける)。
  • 実装でグローバル変数を非表示にし、アクセサー関数を読み取り/書き込みに使用します。
  • 継承の観点からではなく、構成の観点から考えてください。一般的なルールとして、CでC++を模倣しようとしないでください。これは、読み取りと保守が非常に困難です。

学習する時間があれば、必須のpackage(モジュールインターフェイス)とpackage body(モジュール実装)を使用して、Adaアプリがどのように構成されているかを見てください。

これはコーディング用です。

維持するために(一度コーディングすると、数回維持することに注意してください)コードを文書化することをお勧めします Doxygen は私にとっていい選択です。また、リファクタリングできる強力な回帰テストスイートを構築することをお勧めします。

49
mouviciel

OOテクニックはCに適用できないというのは一般的な誤解です。ほとんどの場合、ジョブ専用の構文を持つ言語よりも少し扱いに​​くいというだけです。

堅牢なシステム設計の基盤の1つは、インターフェイスの背後に実装をカプセル化することです。 _FILE*_およびそれと連携する関数(fopen()fread()など)は、カプセル化をCで適用してインターフェイスを確立する方法の良い例です。 (もちろん、Cにはアクセス指定子がないため、_struct FILE_内で誰も覗かないように強制することはできませんが、マゾヒストのみがそうするでしょう。)

必要に応じて、関数ポインターのテーブルを使用してCで多態的な動作を実現できます。はい、構文はいですが、効果は仮想関数と同じです:

_struct IAnimal {
    int (*eat)(int food);
    int (*sleep)(int secs);
};

/* "Subclass"/"implement" IAnimal, relying on C's guaranteed equivalence
 * of memory layouts */
struct Cat {
    struct IAnimal _base;
    int (*meow)(void);
};

int cat_eat(int food) { ... }
int cat_sleep(int secs) { ... }
int cat_meow(void) { ... }

/* "Constructor" */
struct Cat* CreateACat(void) {
    struct Cat* x = (Cat*) malloc(sizeof (struct Cat));
    x->_base.eat = cat_eat;
    x->_base.sleep = cat_sleep;
    x->meow = cat_meow;
}

struct IAnimal* pa = CreateACat();
pa->eat(42);                       /* Calls cat_eat() */

((struct Cat*) pa)->meow();        /* "Downcast" */
_
30
j_random_hacker

すべての良い答え。

「データ構造の最小化」のみを追加します。これはCではさらに簡単かもしれません。C++が "C with classes"である場合、OOPは頭の中のすべての名詞/動詞をクラス/メソッドに変えることを奨励しようとしているためです。それは非常に無駄です。

たとえば、ある時点での温度測定値の配列があり、それらをWindowsで折れ線グラフとして表示するとします。 Windowsにはペイントメッセージがあり、受信すると、LineTo関数を実行して配列をループし、データをスケーリングしてピクセル座標に変換します。

私が何度も見たことがあるのは、チャートは点と線で構成されているため、人々はそれぞれがDrawMyselfが可能な点オブジェクトと線オブジェクトで構成されるデータ構造を構築し、それを永続的にするという理論に基づいていますどういうわけか「より効率的」であるか、グラフの一部にマウスを合わせてデータを数値で表示する必要があるかもしれないので、オブジェクトにメソッドを組み込み、それを処理しますさらに多くのオブジェクトを作成および削除する必要があります。

そのため、非常に読みやすく、オブジェクトの管理にかかる時間の90%を費やすだけの膨大な量のコードが作成されます。

これらはすべて、「グッドプログラミングプラクティス」と「効率」の名の下に行われます。

少なくともCでは、シンプルで効率的な方法がより明白になり、ピラミッドを構築する誘惑が少なくなります。

12
Mike Dunlavey

GNUコーディング標準 は数十年にわたって進化してきました。手紙を読んでいない場合でも、読むことをお勧めします。それらで提起されたポイントについて考えることは、あなた自身のコードをどのように構築するかについてより強固な基礎を与えます。

11
user25148

カプセル化は、開発言語に関係なく、常に開発を成功させるための鍵です。

Cで「プライベート」メソッドをカプセル化するために私が使用したトリックは、「。h」ファイルにプロトタイプを含めないことです。

3
Nate

人気のあるオープンソースCプロジェクトのコードをチェックすることをお勧めします。そして、彼らがそれを整理する方法を参照してください。

3
Ivan Krechetov

複雑なアプリケーションの数のルール:読みやすくする必要があります。

複雑なアプリケーションを簡単にするために、 Divide and conquer を使用します。

3
MrValdez

コードをJavaまたはC++で構成する方法を知っている場合は、Cコードで同じ原則に従うことができます。唯一の違いは、あなたの側にコンパイラがなく、慎重にすべてを手動で行う必要があります。

パッケージとクラスがないため、モジュールを慎重に設計することから始める必要があります。最も一般的なアプローチは、モジュールごとに個別のソースフォルダーを作成することです。異なるモジュール間でコードを区別するには、命名規則に依存する必要があります。たとえば、すべての関数の前にモジュールの名前を付けます。

Cでクラスを持つことはできませんが、「抽象データ型」を簡単に実装できます。抽象データ型ごとに.Cおよび.Hファイルを作成します。必要に応じて、パブリックファイルとプライベートファイルの2つのヘッダーファイルを作成できます。エクスポートする必要があるすべての構造、定数、および関数は、パブリックヘッダーファイルに送られるという考え方です。

ツールも非常に重要です。 Cの便利なツールは lint です。これは、コードの悪臭を見つけるのに役立ちます。使用できる別のツールはDoxygenで、これは documentation の生成に役立ちます。

3
kgiannakakis

最初のステップとして、C/C++の教科書を読むことをお勧めします。たとえば、C Primer Plusは良いリファレンスです。例を見ることで、Java OOをCのような手続き型言語にマッピングする方法についてのアイデアとアイデアが得られます。

2
Tosa