C / C ++。 コマンドライン解析方法

少し前まで、職場で、C ++ Builder環境でプログラムを作成するタスクに直面していましたが、コマンドラインを解析する必要が生じた瞬間がありました。 魔法はタスクにも結び付けられました。「すべてのソースを使用できます。 ここにあります:... "。 まず最初に、私はもちろんそのアドレスに登りました...そしてそこにひどく分岐するコード構造を見つけました。それを見つけようとし、自分用にカスタマイズするのは地獄だと決めました。 そのため、C ++ Builderとコマンドライン引数のみのために、Qtベースのシグナルとスロットのシステムに似たものを書くことが思いつきました。
それでは始めましょう。 アイデアは次のとおりです。コマンドライン分析では、引数に特殊文字が含まれているかどうかを確認します(私の場合は「-」でした-Linux標準を採用しました)。 これに応じて、引数はパラメーターの名前またはその値として読み取られます。 連想配列は、処理関数の呼び出しに使用されます。 キーが使用可能なパラメーターの名前であり、値が特定のパラメーターの処理関数のアドレスである配列。 それは、一般に、すべてです。 実装に取り​​かかりましょうか?

進む。 楽器の研究から始めましょう。 C ++ Builderは、マップタイプ(map.hで宣言)を使用して、連想配列を処理します。

#include <map.h>

さらにヘルプ。 タイプを宣言します。

typedef map <AnsiString, int*> TFuncTable;

そして、クラスのタイプのインスタンス:

TFuncTable funcTable;

ここでは、AnsiStringがキーとして使用され(fort me std :: string)、値はint *です(ところで、64ビットシステムでは機能しない場合があります)。 次に、このハッシュに挿入する方法を見てみましょう。 それほど単純ではなく、殺すのに約2時間かかったことが判明しました。しかし、次のようにしました。

int *addr = (int*)&myFunction;
funcTable.insert(TFuncTable::value_type(AnsiString("-myParam"), addr));

TFuncTable :: value_type()に注意を払う価値があります-なぜ、私は正直に理解していませんでしたが、明らかに、これはプログラムがコンパイルさえしない何らかのタイプのマッチングです。
だから、配列を初期化-素晴らしい。 彼はどう見える? はい、このようなもの:

funcTable[“-myParam”] == 0xABCDEF // -

ゆっくりですが確実に、私たちはこの経済全体の利用に近づいています。 そのようなアルゴリズムのマイナス1つはすぐに言及する価値があります。処理関数は同じ種類でなければなりません。つまり、関数型を宣言します。

typedef void (*TFunc)(AnsiString param);

ハンドラーを作成する際にそれに従ってください。 そのようなハンドラーの例:

void myFunction(AnsiString name)
{
MainForm->setTestName(name);
}

しかし、これは単純なハンドラです。 のようなものがパラメータとして提供される場合、おそらくそれはより困難になります。

"param1,param2,param3"

実際の例については、/ etc / fstab-Linuxファイルをご覧ください。
さて、パラメータ名でハッシュから関数を開始する方法を説明します。 はい、しかしその前に、初期化手順全体をヒープに置く価値があると思います。
  1. 地図が含まれています
  2. 宣言された型ハッシュ、この型のインスタンスを宣言しました。
  3. 彼らは関数型を宣言し、この型に準拠したパラメーターハンドラー関数を作成しました。
  4. ハッシュを埋めました。

これで、コマンドライン自体の処理機能を開始できます。 これは、引数がパラメーターの名前または値であるかどうかを計算アルゴリズムがどのように見ているかです:

bool TMainForm::parseParams()
{
int argc;
TFunc srvFunc;
LPWSTR *cmdLine = CommandLineToArgvW(GetCommandLineW(), &argc);
int iter = 1;

for(int i = 1; i < argc; i += iter)
{
AnsiString param = "";
AnsiString paramName = cmdLine[i];
if(i < argc - 1)
{
if(AnsiString(cmdLine[i + 1])[1] == '-')
iter = 1;
else
{
param = cmdLine[i + 1];
iter = 2;
}
}

if(funcTable.find(paramName) == funcTable.end())
{
Out(" " + paramName);
return false;
}
srvFunc = (TFunc)funcTable[paramName];
srvFunc(param);
}
return true;
}


何が何ですか:
LPWSTR * cmdLine = CommandLineToArgvW(GetCommandLineW()、&argc); -ボーランドのヘルプでもこれはすべて泥だらけですが、そのような変換のシーケンスが標準のargcとargvを生成するという事実にすべてが要約されているので、先に進みましょう。
Out()は特殊な入出力関数です。 特定のトピックについては関心がありません。
文字列引数で「-」記号を検索する手順を伝える必要はありません-それは平凡です。 ここで最も興味深いのは:

srvFunc = (TFunc)funcTable[paramName];
srvFunc(param);

そのため、関数ハンドラーが起動されます。 シンプルでしょ? そして、1000番目の膝までは野生の枝はありません。

では、何がありますか? 私は州で働いています。 オフィス、そしてそれは私がそこに残るつもりはない理由です。 つまり、私の後に来た従業員は、ハンドラーを簡単に記述し、アドレスをハッシュに入れるので、コマンドラインアナライザーについて考える必要はありません。 これがそのような算術です。

Source: https://habr.com/ru/post/J120396/


All Articles