Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用c#中的pinvoke在64位上调用sprintf和friends_C#_64 Bit_Pinvoke - Fatal编程技术网

使用c#中的pinvoke在64位上调用sprintf和friends

使用c#中的pinvoke在64位上调用sprintf和friends,c#,64-bit,pinvoke,C#,64 Bit,Pinvoke,在C中使用pinvoke调用snwprintf时,我遇到了一个有趣的问题。它适用于整数类型,但不适用于浮点数 这是在64位Windows上,在32位Windows上运行良好 下面是我的代码,请记住,这是一个人为的例子来显示我看到的行为 class Program { [DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private st

在C中使用pinvoke调用snwprintf时,我遇到了一个有趣的问题。它适用于整数类型,但不适用于浮点数

这是在64位Windows上,在32位Windows上运行良好

下面是我的代码,请记住,这是一个人为的例子来显示我看到的行为

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,到目前为止,我被难住了。

uint是32位。snprintf的长度参数是size_t,在64位进程中为64位。将第二个参数更改为IntPtr,它是与size\u t最接近的.NET等效值


此外,您需要预先分配StringBuilder。当前您的缓冲区溢出。

我不太清楚为什么您的调用不起作用,但在x86和x64中都能正常工作

以下代码确实可以正常工作:

class Program
{
    [DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern int _snwprintf_s([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr bufferSize, IntPtr length, String format, int p);

    [DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern int _snwprintf_s([MarshalAs(UnmanagedType.LPWStr)] StringBuilder str, IntPtr bufferSize, IntPtr length, String format, double p);

    static void Main(string[] args)
    {
        // Preallocate this to a given length
        StringBuilder str = new StringBuilder(100);
        double d = 1.4;
        int i = 7;
        float s = 1.1f;

        // No need for box/unbox
        _snwprintf_s(str, (IntPtr)100, (IntPtr)32, "%10.1lf", d);
        Console.WriteLine(str.ToString());

        _snwprintf_s(str, (IntPtr)100, (IntPtr)32, "%10.1f", s);
        Console.WriteLine(str.ToString());

        _snwprintf_s(str, (IntPtr)100, (IntPtr)32, "%10d", i);
        Console.WriteLine(str.ToString());

        Console.ReadKey();
    }
}

在第二个函数的最后一个参数上尝试Marshallas R8(表示实/浮8(双精度))。

可以使用undocumented\uu arglist关键字:

using System;
using System.Text;
using System.Runtime.InteropServices;

class Program {
    [DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern int _snwprintf(StringBuilder str, int length, String format, __arglist);

    static void Main(string[] args) {
        Double d = 1.0f;
        Int32 i = 1;
        String s = "nobugz";
        StringBuilder str = new StringBuilder(666);

        _snwprintf(str, str.Capacity, "%10.1lf %d %s", __arglist(d, i, s));
        Console.WriteLine(str.ToString());
        Console.ReadKey();
    }
}

请不要使用它。

看看这两篇文章:

(这实际上是CodeProject文章的注释)


什么样的恶魔能把你带到pinvoke C runtime printf家族?C调用约定,变量参数,非OS部署DLL,就像是一场完美风暴!string.Format对你来说还不够好吗?@Remus-我意识到这不是一件好事,而且会自找麻烦,但是有时候我们都不得不接受现有的代码。此外,尽管它可能有多可怕,但在我看来它仍然应该工作。@zneak-我希望使用string.Format而不是这个,但在这种情况下,我必须使用printf样式的格式说明符。如果这不起作用,我正在考虑的另一个解决方案是编写一个函数,将printf格式的字符串转换为c#one,然后使用string.format。@各位,我同意bde,在这里我们应该尽力帮助他,同意他当然知道自己在做什么,有时你不能花费数千美元重写整个应用程序,但我们需要足够聪明,以节省在我们的软件中编写补丁的时间。尝试过,同样的问题。不过我会更新我的示例,它无论如何都应该使用IntPtr。这不起作用。如果我使用单而不是双,同样的问题也会发生。不过,我会将示例更改为使用lf。请参阅主要评论,了解我为什么要这样做。@bde:我刚刚重述了我的答案。那里发布的代码在x86和x64中工作,没有问题。我刚刚阅读了msdn帮助,第二个参数应该是参数数组的形式,我不知道如何将其封送到c的参数数组,即使您以双精度发送参数,可能运行时不希望它以相同的形式发送,我想知道int是如何工作的,double也应该工作。尝试将它作为双参数的第一个项目发送到最后一个参数,并尝试PARAMPARAM.C和C++ VARARGS在.NET参数数组下面非常不同。sprintf肯定使用了pass-by-value。对于重复的帖子,很抱歉,在发布我的答案时没有看到您的_参数列表:)我今天早些时候确实尝试过,但我无法让它工作。这个示例代码为我做的就是打印格式字符串。也许我错过了什么。我同意我不想使用这种方法。@bde:Project+Properties,Application选项卡,Platform Target=x86。这就是危险,解决了它,但这很奇怪。所以x64不支持__arglist这个秘密?@bde:我的解释是,_arglist不能正确地使用x64调用约定。这是一个棘手的问题,因为前4个参数是在寄存器中传递的。