0

C# プロジェクトで C ライブラリを使用する必要があります。どのようにできるのか?

より具体的に言うと、効率の理由から、strtod関数を使用して文字列から double 値を抽出する必要があります (この "9.63074,9.63074 -5.55708e-006 0 ,0 1477.78" など)。この操作を最適化する方法について提案がある場合は恥ずかしがり屋ではありませんが、主な質問はタイトルで指定されたままです。

4

5 に答える 5

6

strtodp / 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、偽のコンマのためにそれをトークン化することはありません。

于 2012-04-18T17:36:42.677 に答える
2

まず、マネージドコードとアンマネージドコード間の呼び出しが比較的高価であり、無料ではないという事実を理解していません。strtodですから、あなたが私たちに言ったことから、あなたはマネージコードから何度も電話をかけるように思えます。テストする必要がありますが、ピンボークペナルティによってパフォーマンスの向上が無効になる場合があります。

strtodまた、ユースケースで管理対象バージョンよりも高速であることを確認するために実際にテストしましたか?私のテストでdouble.Parseは、実際には100,000回の反復よりも高速であることが示されました。strtod約54ミリ秒かかり、double.Parse3回の実行で約15分かかりました。必要に応じてコードを提供できます。)

これは、テストされていないコードを最適化しようとする誤った試みのように聞こえます。正しい問題を解決していると確信していますか?

于 2012-04-18T17:45:17.203 に答える
1

なぜ使用しないのdouble.Parse()ですか?

double asDouble = double.Parse(myInput);
于 2012-04-18T17:28:48.633 に答える
0

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コレクションに追加します。文字列に対して正規表現コードをテストしなかったことに注意してください。

于 2012-04-18T18:23:30.783 に答える
0

.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() を見ることを強くお勧めします。

于 2012-04-18T17:29:20.980 に答える