-1

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

4

1 回答 1

1

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

  1. msvcrt.dllC++ 运行时可能会发生变化,因此任何依赖它的代码都可能会在未来发生故障。
  2. 的最后一个参数memcmp有类型size_t。这与指针大小相同,因此映射到UIntPtr. 请记住,C#long是 64 位宽的。
  3. 在 ap/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();
    }
}

这段代码肯定不是很有效,更不用说它很hacky了。我建议您坚持使用纯 .net 代码。

于 2015-10-06T08:26:11.677 回答