0

我需要在 C# 项目中使用 C 库。我能怎么做?

更具体地说:出于效率的原因,我需要使用strtod函数从字符串中提取双精度值(例如“9.63074,9.63074 -5.55708e-006 0 ,0 1477.78”)。如果您对如何优化此操作有建议,请不要害羞,但主要问题仍然是标题指定的问题。

4

5 回答 5

6

我认为 p/invoking to 不太可能strtod比纯 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从 C# 调用的方式,请记住,我建议您不要在实际代码中使用这种方法。

[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);

我将字符串作为 an 传递,IntPtr因为您会strtod反复调用以遍历整个缓冲区。我没有在这里展示,但如果你要使用它,endptr那么你需要按照我的说明进行操作。

当然,要strtod有效地远程使用,您需要访问errno全局变量。您需要处理全局变量这一事实应该足以警告这里是龙。更重要的是,通过提供的错误报告errno非常有限。但是,如果你想要它,这里是:

[DllImport(@"msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int _get_errno();

最后一点。您建议的输入字符串是

"9.63074,9.63074 -5.55708e-006 0 ,0 1477.78"

strtod由于虚假逗号而不会对其进行标记。

于 2012-04-18T17:36:42.677 回答
2

首先,您没有意识到托管代码和非托管代码之间的调用相对昂贵,它不是免费的。因此,根据您告诉我们的内容,听起来您strtod将从托管代码中多次调用。您必须对其进行测试,但 pinvoke 惩罚可能会抵消任何性能提升。

此外,您是否进行了实际测试以确保strtod在您的用例中比托管版本更快?我的测试表明,超过 100,000 次迭代double.Parse实际上更快。strtod耗时约 54 毫秒,double.Parse三轮运行约 15 毫秒。如果您愿意,我可以给您代码。)

这听起来像是在优化一段甚至没有经过测试的代码的错误尝试。你确定你正在解决正确的问题吗?

于 2012-04-18T17:45:17.203 回答
1

为什么不使用double.Parse()

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

要回答如何在 .NET 中使用 C 库的问题:您可以做的一件事是创建一个您想要的 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 回答
0

David 通过 p/invoke 向您展示了如何做到这一点。但是,.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));
    } 

此代码会将字符串中的所有双精度值添加到通用List集合中。注意我没有针对您的字符串测试正则表达式代码,但这给了您一个想法。

于 2012-04-18T18:23:30.783 回答