在 C# 中使用 pinvoke 调用 64 位上的 sprintf 和朋友
我在 C# 中使用 pinvoke 调用 _snwprintf 时遇到一个有趣的问题。它适用于整数类型,但不适用于浮点数。
这是在 64 位 Windows 上运行的,在 32 位上运行良好。
我的代码如下,请记住,这是一个人为的示例,旨在展示我所看到的行为。
class Program
{
[DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern int _snwprintf([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr length, String format, int p);
[DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern int _snwprintf([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr length, String format, double p);
static void Main(string[] args)
{
Double d = 1.0f;
Int32 i = 1;
Object o = (object)d;
StringBuilder str = new StringBuilder(32);
_snwprintf(str, (IntPtr)str.Capacity, "%10.1lf", (Double)o);
Console.WriteLine(str.ToString());
o = (object)i;
_snwprintf(str, (IntPtr)str.Capacity, "%10d", (Int32)o);
Console.WriteLine(str.ToString());
Console.ReadKey();
}
}
这个程序的输出是
0.0
1
它应该在第一行打印 1.0 而不是 0.0,到目前为止我很困惑。
I am having an interesting problem with using pinvoke in C# to call _snwprintf. It works for integer types, but not for floating point numbers.
This is on 64-bit Windows, it works fine on 32-bit.
My code is below, please keep in mind that this is a contrived example to show the behavior I am seeing.
class Program
{
[DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern int _snwprintf([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr length, String format, int p);
[DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern int _snwprintf([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr length, String format, double p);
static void Main(string[] args)
{
Double d = 1.0f;
Int32 i = 1;
Object o = (object)d;
StringBuilder str = new StringBuilder(32);
_snwprintf(str, (IntPtr)str.Capacity, "%10.1lf", (Double)o);
Console.WriteLine(str.ToString());
o = (object)i;
_snwprintf(str, (IntPtr)str.Capacity, "%10d", (Int32)o);
Console.WriteLine(str.ToString());
Console.ReadKey();
}
}
The output of this program is
0.0
1
It should print 1.0 on the first line and not 0.0, and so far I am stumped.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我不太清楚为什么您的呼叫不起作用,但 这些的安全版本方法 在 x86 和 x64 中都能正常工作。
以下代码确实可以正常工作,如预期的那样:
I'm not exactly sure why your calls do not work, but the secured versions of these methods do work properly in both x86 and x64.
The following code does work, as expected:
可以使用未记录的 __arglist 关键字:
请不要使用它。
It is possible with the undocumented __arglist keyword:
Please don't use that.
uint 是 32 位。 snprintf的长度参数是size_t,在64位进程中是64位。将第二个参数更改为 IntPtr,它是最接近 size_t 的 .NET 等效项。
此外,您需要预先分配 StringBuilder。目前您有缓冲区溢出。
uint is 32 bits. The length parameter of snprintf is size_t, which is 64 bits in 64 bit processes. Change the second parameter to IntPtr, which is the closest .NET equivalent of size_t.
In addition, you need to preallocate your StringBuilder. Currently you have a buffer overrun.
尝试在第二个函数的最后一个参数上使用 MarshalAs R8(即实数/浮点 8(双精度))。
Try MarshalAs R8 (Thats for real/floating 8 (which is double)) on last parameter in second function.
看一下这两篇文章:
http://www. codeproject.com/Messages/2840231/Alternative-using-MSVCRT-sprintf.aspx (这实际上是 CodeProject 文章的注释)
http://bartdesmet.net/blogs/bart/archive/2006/09/28/4473.aspx
Take a look at these two articles:
http://www.codeproject.com/Messages/2840231/Alternative-using-MSVCRT-sprintf.aspx (this is actually note to CodeProject article)
http://bartdesmet.net/blogs/bart/archive/2006/09/28/4473.aspx