c#中PInvoke中的memcmp不能正常工作于大于4x4的数组
本文关键字:于大于 大于 4x4 数组 工作 memcmp 中的 不能 常工作 PInvoke | 更新日期: 2023-09-27 18:16:20
PInkove部分摘自一些SO答案(抱歉,我丢失了原始链接)。
下面是完整的程序。输出为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会这样做?
你的代码有很多问题。下面是我看到的:
-
msvcrt.dll
c++运行时可能会发生变化,所以任何依赖于它的代码都有可能在未来被破坏。 -
memcmp
的最终参数类型为size_t
。这与指针的大小相同,因此映射到UIntPtr
。请记住c#long
是64位宽的。 - 在p/invoke中使用
Array
充其量是可疑的。谁知道那是什么?我希望它作为指向类的内部表示的指针进行封送。它肯定不会作为指向数组开头的指针封送。 -
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代码。