2015-10-05 81 views
-1

PInkove部分取自一些SO回答(对不起,我失去了原来的链接)。来自PInvoke的memcmp在C#中对于大于4x4的数组无法正常工作

以下是完整的程序。输出是false

using System; 
using System.Runtime.InteropServices; 

namespace Memcpy 
{ 
    class Program 
    { 
     [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] 
     private static extern int memcmp(Array b1, Array b2, long count); 

     public static bool CompareArrays(Array b1, Array b2) 
     { 
      // Validate buffers are the same length. 
      // This also ensures that the count does not exceed the length of either buffer. 
      return b1.Length == b2.Length && memcmp(b1, b2, b1.Length) == 0; 
     } 

     static void Main(string[] args) 
     { 
      var array1 = new int[,] 
      { 
       {0, 0, 0, 0, 0}, 
       {0, 0, 0, 0, 0}, 
       {0, 0, 0, 0, 0}, 
       {0, 0, 0, 0, 0}, 
      }; 

      var array2 = new int[,] 
      { 
       {0, 0, 0, 0, 0}, 
       {0, 0, 0, 0, 0}, 
       {0, 0, 0, 0, 0}, 
       {0, 0, 0, 0, 0}, 
      }; 

      Console.WriteLine(CompareArrays(array1, array2)); 
     } 
    } 
} 

如果我改变阵列的大小在4x4输出变为true

为什么memcmp这样的行为?

+0

你认为b1.Length的价值是什么? – pm100

+0

'CompareArrays'里面的长度都是相等的,memcmp的结果不是= 0。 只需设置一个断点: 'b1.Length = 20' 'b2.Length = 20' –

+1

'memcmp'需要两个空指针和以字节为单位的长度。是什么让你认为数组的'Length'属性是以字节为单位的长度?不是,它是数组中元素的数量。另外,你可能想调用'memcmp',因为你认为这是一个有效的函数?它是,但生成的编组代码可能不是!事实上,我认为编组代码可能是这里的罪魁祸首。 –

回答

1

你的代码有很多问题。以下是我所能看到的:

  1. msvcrt.dll C++运行时可能会发生变化,因此您所依赖的任何代码都有可能在将来破坏。
  2. 最终参数memcmp的型号为size_t。这与指针大小相同,因此映射到UIntPtr。请记住,C#long是64位宽。
  3. 在p/invoke中使用Array充其量是可疑的。谁知道那个元帅呢?我希望这些人员能够成为班级内部表征的指针。它肯定不会作为指向数组开头的指针编组。
  4. memcpy需要比较的字节数,而不是数组的长度。您需要将数组的长度乘以元素的大小以获取字节数。

要使您的程序正常工作,您需要解决这些问题。撇开使用MSVCRT的,你可以纠正你这样的代码:

[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] 
private static extern int memcmp(IntPtr b1, IntPtr b2, UIntPtr count); 

public static bool CompareArrays(Array b1, Array b2) 
{ 
    if (b1.Length != b2.Length) 
     return false; 
    if (!b1.GetType().GetElementType().Equals(b2.GetType().GetElementType())) 
     return false; 

    GCHandle gch1 = GCHandle.Alloc(b1, GCHandleType.Pinned); 
    try 
    { 
     GCHandle gch2 = GCHandle.Alloc(b2, GCHandleType.Pinned); 
     try 
     { 
      return memcmp(gch1.AddrOfPinnedObject(), gch2.AddrOfPinnedObject(), 
       (UIntPtr)(b1.Length * Marshal.SizeOf(b1.GetType().GetElementType()))) == 0; 
     } 
     finally 
     { 
      gch2.Free(); 
     } 
    } 
    finally 
    { 
     gch1.Free(); 
    } 
} 

此代码是肯定不是非常有效的,更何况这是非常哈克。我建议你坚持纯净的.net代码。

相关问题