Use C Library in .NET

不打扰是莪最后的温柔 提交于 2019-12-13 03:20:58

问题


I need to use the C library in a C# project. How can I do?

To be more specific: for reasons of efficiency I need to use the strtod function to extract double values from a string (like this "9.63074,9.63074 -5.55708e-006 0 ,0 1477.78"). If you have suggestions about how to optimize this operation do not be shy, but the main question remains that specified by title.


回答1:


I think it very unlikely that p/invoking to strtod would be more efficient than a pure C# solution. There is an overhead in managed/unmanaged transitions and I would think that would be significant for something as trivial as strtod. Myself I would use a C# tokenizer, combined with double.Parse.

The simplest C# tokenizer is String.Split() which yields this routine:

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;
}

However, since I enjoy p/invoke, here's how you would call strtod from C#, bearing in mind that I recommend you don't use this approach in real code.

[DllImport(@"msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern double strtod(IntPtr str, ref IntPtr endptr);

You can call it like this:

IntPtr str = Marshal.StringToHGlobalAnsi(inputStr);
IntPtr endptr = IntPtr.Zero;
double val = strtod(str, ref endptr);
Marshal.FreeHGlobal(str);

I'm passing the string as an IntPtr because you would be calling strtod repeatedly to walk across the entire buffer. I didn't show that here, but if you are going to make any use of endptr then you need to do it as I illustrate.

Of course, to use strtod remotely effectively you need to gain access to the errno global variable. The very fact that you need to deal with a global variable should be warning enough that here be dragons. What's more, the error reporting offered through errno is exceedingly limited. However, if you want it, here it is:

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

One final point. Your suggested input string is

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

but strtod won't tokenize that because of the spurious commas.




回答2:


First, you are not appreciating the fact that calls between managed and unmanaged code are relatively expensive, it is not free. So, from what you have told us, it sounds like you will be calling strtod many times from managed code. You'd have to test it, but the pinvoke penalty may negate any performance gains.

Also, have you actually tested to ensure that strtod is faster in your use case than the managed version would be? My testing showed that double.Parse is actually faster over 100,000 iterations. (strtod took ~54ms, double.Parse took ~15 over three runs. I can give you the code if you like.)

This sounds like a misguided attempt at optimizing a piece of code that hasn't even been tested. Are you sure you're solving the right problem?




回答3:


Why not use double.Parse()?

double asDouble = double.Parse(myInput);



回答4:


To answer the question of how to use a C library in .NET: One thing that you can do is to create a function the C calls that you desire. From there, you'll need to build it as a DLL. Once that is done, you'll be able to P/Invoke it from C#.

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

Another possibility is to build this as a mixed assembly.

http://msdn.microsoft.com/en-us/library/x0w2664k.aspx

That said, in your specific case, I would highly suggest looking at double.Parse() unless there is good reason otherwise.




回答5:


David showed you how to do it via p/invoke. However, the .NET way to do it would be to use Regex. Something like the following might work for you:

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

This code will add all the doubles in a string into a generic List collection. Note I didn't test the Regex code against your string, but this gives you an idea.



来源:https://stackoverflow.com/questions/10214630/use-c-library-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!