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会这样做?

c#中PInvoke中的memcmp不能正常工作于大于4x4的数组

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

  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代码。