2

私はCでミニシェルを構築していますが、グローバル変数(正確には3)を使用することで簡単に修正できると思われる障害に到達しました。グローバルが必要だと思う理由は、代わりに、これらの変数をプログラム内のほぼすべての関数に渡すことになるからです。

変数は、mainargc、mainargv、およびshiftedMArgVです。最初の2つは、それぞれ引数の数とmainに渡される引数リストです。変数shiftedMArgVは引数リストですが、シフトされている可能性があります。組み込み関数shiftおよびunshiftを作成しようとしていますが、shiftedMArgVが異なる引数を指すようになります。

それで、これらを単にグローバルにするのは愚かなことでしょうか?そうしないと、非常に大量のコードを修正する必要があり、それらをグローバルにすることで何かが失われるかどうかはわかりません。

それらをグローバルにすると、メインヘッダーファイルからグローバルにするのはばかげていますか?

助けてくれてありがとう、何か説明が必要な場合はただ聞いてください。

4

5 に答える 5

5

グローバル変数の代わりに、「グローバル関数」を検討してください。

extern int    msh_mainArgC(void);
extern char **msh_mainArgV(void);
extern char **msh_shiftedArgV(void);

これらの関数の実装は簡単ですが、メモリへのアクセスを制御できます。また、何か凝ったことをする必要がある場合は、関数の実装を変更できます。(違いをわかりやすくするために、CとVを大文字にすることを選択しました。8〜12文字の名前の最後の文字だけが異なると、違いを見つけるのが難しくなります。)

これらの関数を定義する実装ファイルがあります。そのファイルには、関連情報を格納する静的変数と、変数を設定または操作するための関数があります。原則として、十分な数constの修飾子をたたくと、呼び出し元のコードがデータを変更できないようにすることができます。ただし、そうするように設計された関数を使用する場合を除きます(または、キャストを使用して定数を削除します)。

これがあなたにとって価値があるかどうかは議論の余地があります。しかし、そうかもしれません。これは、より「オブジェクト指向」の操作スタイルです。考慮しないままにするのではなく、検討してから破棄することもできます。

これらの関数を使用するサブシステムには、グローバル値を収集し、それらを従属関数に渡す1つの関数がある場合があることに注意してください。これにより、部下は値がどこから来たのかを知る必要がなくなります。それらを正しく操作するだけです。グローバル変数がある場合は、エイリアシングについて心配する必要があります—値(グローバル変数のコピー)が渡される関数ですが、グローバル変数にもアクセスします。関数を使用すると、同じようにそれを心配する必要はありません。

于 2012-11-03T22:29:24.190 に答える
2

愚かではありませんが、注意して進めてください。

グローバルが通常避けられる理由は、グローバルを決して使用してはならないということではなく、グローバルを使用することで、プログラマーが頻繁にクラッシュして燃えるようになるためです。経験を通して、正しい時と間違った時の違いを学びます。

解決しようとしている問題について深く考え、この問題を解決するために作成したコードを検討し、このコードの将来についても検討し(つまり、保守性を損なう)、グローバルが避けられないか、より優れていると感じた場合コード化されたソリューションを表す場合は、グローバルを使用する必要があります。

後で、クラッシュして燃えるかもしれませんが、その経験は、後でより良い選択が何であったかを見極めるのに役立ちます。逆に、グローバルを使用しないとクラッシュやバーニングが発生する可能性があると思われる場合は、これよりも、グローバルを使用する必要があるという以前の経験があります。あなたはそのような本能を信頼すべきです。

ダイクストラは、声明が引き起こす可能性のある害について論じている論文を持っていますが、私の意見では、彼の議論は、グローバルに関する私たちの困難のいくつかを説明しています。goto読む価値があるかもしれません。

この答えこの答えも役に立つかもしれません。

于 2012-11-03T22:18:42.330 に答える
1

グローバルは、論理的な意味で本当にグローバルである限り問題ありません。単にあなたの生活を楽にするための手段ではありません。たとえば、グローバルは、プログラムが実行される環境、つまり、アプリのシステムレベルに関連する属性を表すことができます。

于 2012-11-03T22:12:49.463 に答える
1

私がこれまでに使用したほとんどすべての複雑なソフトウェアには、明確に定義されたグローバルのセットがありました。それは何も悪いことではありません。それらはほんの一握りから約十数までの範囲です。後者の場合、それらは通常、構造体に論理的にグループ化されます。

グローバルは通常、ヘッダーファイルでexternとして公開され、ソースファイルで定義されます。グローバルはスレッド間で共有されるため、スレッドローカルストレージで宣言する方が理にかなっている場合を除き、保護する必要があることを覚えておいてください。

于 2012-11-03T22:15:23.280 に答える
1

シェルの場合、これよりもはるかに多くの状態があります。再マップされたファイル記述子(さまざまな理由で追跡する必要があります)、trap処理、setオプション、環境およびシェル変数の状態があります...

一般に、グローバル変数は間違った解決策です。代わりに、すべての状態をある種のコンテキスト構造に保持する必要があります。このコンテキストへのポインタはどこにでも渡されます。これは優れたプログラム設計であり、通常、同じプロセスで同じコードの複数のインスタンスを実行できます(たとえば、複数のインタープリター、複数のビデオデコーダーなど)。

そうは言っても、シェルは非常に特殊なケースです構造に保持できないグローバル状態の例:信号処理、ファイル記述子とマッピング、子プロセス、プロセスグループ、制御端末など。エミュレートできるように、追加のレイヤーを使用してこれらの多くを抽象化できる場合があります。単一のプロセス内に複数存在する可能性のあるクリーンなコンテキストを維持しながら必要な動作を行いますが、これは従来のシェルを作成するよりもはるかに難しい作業です。そのため、グローバル変数を使用してシェルを「怠惰な方法」で作成するための余裕を持たせることができます。ただし、これが学習演習である場合は、グローバル変数または状態を導入するたびに、それを行う理由、およびグローバル状態がなくてもプログラムを異なる方法で実装できる可能性がある方法を注意深く特定するようにしてください。これは、将来的に非常に役立ちます。

于 2012-11-04T00:51:54.243 に答える