-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. C++ ランタイムはmsvcrt.dll変更される可能性があるため、これに依存するコードは将来壊れる可能性があります。
  2. memcmphas typeの最終パラメータsize_t。これはポインタと同じサイズなので、 にマップされUIntPtrます。C#longは 64 ビット幅であることに注意してください。
  3. in 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();
    }
}

このコードは非常にハックであることは言うまでもなく、あまり効率的ではありません。純粋な .net コードに固執することをお勧めします。

于 2015-10-06T08:26:11.677 に答える