我需要在 C# 项目中使用 C 库。我能怎么做?
更具体地说:出于效率的原因,我需要使用strtod函数从字符串中提取双精度值(例如“9.63074,9.63074 -5.55708e-006 0 ,0 1477.78”)。如果您对如何优化此操作有建议,请不要害羞,但主要问题仍然是标题指定的问题。
我认为 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
由于虚假逗号而不会对其进行标记。
首先,您没有意识到托管代码和非托管代码之间的调用相对昂贵,它不是免费的。因此,根据您告诉我们的内容,听起来您strtod
将从托管代码中多次调用。您必须对其进行测试,但 pinvoke 惩罚可能会抵消任何性能提升。
此外,您是否进行了实际测试以确保strtod
在您的用例中比托管版本更快?我的测试表明,超过 100,000 次迭代double.Parse
实际上更快。(strtod
耗时约 54 毫秒,double.Parse
三轮运行约 15 毫秒。如果您愿意,我可以给您代码。)
这听起来像是在优化一段甚至没有经过测试的代码的错误尝试。你确定你正在解决正确的问题吗?
为什么不使用double.Parse()
?
double asDouble = double.Parse(myInput);
要回答如何在 .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() ,除非有充分的理由。
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
集合中。注意我没有针对您的字符串测试正则表达式代码,但这给了您一个想法。