2015-10-05 82 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代碼。

相關問題