C# プロジェクトで C ライブラリを使用する必要があります。どのようにできるのか?
より具体的に言うと、効率の理由から、strtod関数を使用して文字列から double 値を抽出する必要があります (この "9.63074,9.63074 -5.55708e-006 0 ,0 1477.78" など)。この操作を最適化する方法について提案がある場合は恥ずかしがり屋ではありませんが、主な質問はタイトルで指定されたままです。
strtod
p / invokingが純粋なC#ソリューションよりも効率的である可能性は非常に低いと思います。マネージド/アンマネージドトランジションにはオーバーヘッドがあり、それは。のような些細なことにとって重要だと思いますstrtod
。私自身は、C#トークナイザーをと組み合わせて使用しdouble.Parse
ます。
最も単純なC#トークナイザーは、次のString.Split()
ルーチンを生成します。
static List<double> getValues(string str)
{
List<double> list = new List<double>();
foreach (string item in str.Split(default(Char[]), StringSplitOptions.RemoveEmptyEntries))
list.Add(double.Parse(item));
return list;
}
ただし、私はp / invokeを楽しんでいるのでstrtod
、実際のコードではこのアプローチを使用しないことをお勧めします。
[DllImport(@"msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern double strtod(IntPtr str, ref IntPtr endptr);
あなたはそれをこのように呼ぶことができます:
IntPtr str = Marshal.StringToHGlobalAnsi(inputStr);
IntPtr endptr = IntPtr.Zero;
double val = strtod(str, ref endptr);
Marshal.FreeHGlobal(str);
バッファ全体をウォークスルーするIntPtr
ために繰り返し呼び出すため、文字列をとして渡します。strtod
ここではそれを示しませんでしたが、それを利用する場合はendptr
、私が説明するようにそれを行う必要があります。
もちろん、リモートで効果的に使用するには、グローバル変数strtod
にアクセスする必要があります。errno
グローバル変数を処理する必要があるという事実は、ここにドラゴンがいることを十分に警告しているはずです。さらに、提供されるエラー報告errno
は非常に限られています。ただし、必要に応じて、次のようになります。
[DllImport(@"msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int _get_errno();
最後にもう1つ。提案された入力文字列は
"9.63074,9.63074 -5.55708e-006 0 ,0 1477.78"
しかしstrtod
、偽のコンマのためにそれをトークン化することはありません。
まず、マネージドコードとアンマネージドコード間の呼び出しが比較的高価であり、無料ではないという事実を理解していません。strtod
ですから、あなたが私たちに言ったことから、あなたはマネージコードから何度も電話をかけるように思えます。テストする必要がありますが、ピンボークペナルティによってパフォーマンスの向上が無効になる場合があります。
strtod
また、ユースケースで管理対象バージョンよりも高速であることを確認するために実際にテストしましたか?私のテストでdouble.Parse
は、実際には100,000回の反復よりも高速であることが示されました。(strtod
約54ミリ秒かかり、double.Parse
3回の実行で約15分かかりました。必要に応じてコードを提供できます。)
これは、テストされていないコードを最適化しようとする誤った試みのように聞こえます。正しい問題を解決していると確信していますか?
なぜ使用しないのdouble.Parse()
ですか?
double asDouble = double.Parse(myInput);
David は、p/invoke を介してそれを行う方法を示しました。ただし、それを行う .NET の方法は、.NET を使用することRegex
です。次のようなものがうまくいくかもしれません:
MatchCollection matches = Regex.Matches(inputString, @".*?([-]{0,1} *\d+.\d+)");
List<double> doubles = new List<double>();
foreach (Match match in matches)
{
string value = match.Groups[1].Value;
value = value.Replace(" ", "");
doubles.Add(double.Parse(value));
}
このコードは、文字列内のすべての double をジェネリックList
コレクションに追加します。文字列に対して正規表現コードをテストしなかったことに注意してください。
.NET で C ライブラリを使用する方法に関する質問に答えるには: できることの 1 つは、必要な C 呼び出し関数を作成することです。そこから、DLL としてビルドする必要があります。これが完了すると、C# から P/Invoke できるようになります。
http://www.codeproject.com/Articles/9826/How-to-create-a-DLL-library-in-C-and-then-use-it-w http://msdn.microsoft.com/en -us/library/ms235282(v=vs.80).aspx
別の可能性は、これを混合アセンブリとして構築することです。
http://msdn.microsoft.com/en-us/library/x0w2664k.aspx
そうは言っても、あなたの特定のケースでは、他に正当な理由がない限り、 double.Parse() を見ることを強くお勧めします。