<p>How can I do this fast?</p>

<p>Sure I can do this:</p>

<pre><code>static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
    if (a1.Length != a2.Length)
        return false;

    for (int i=0; i&lt;a1.Length; i++)
        if (a1[i]!=a2[i])
            return false;

    return true;
}
</code></pre>

<p>But I'm looking for either a <a href="https://en.wikipedia.org/wiki/Standard_Libraries_%28CLI%29#Base_Class_Library" rel="noreferrer">BCL</a> function or some highly optimized proven way to do this.</p>

<pre><code>java.util.Arrays.equals((sbyte[])(Array)a1, (sbyte[])(Array)a2);
</code></pre>

<p>works nicely, but it doesn't look like that would work for x64.</p>

<p>Note my super-fast answer <a href="https://stackoverflow.com/a/8808245/4489">here</a>.</p>

[{'answer_id': 43300, 'author': 'gil', 'author_id': 195, 'author_profile': 'https://Stackoverflow.com/users/195', 'pm_score': 3, 'selected': False, 'text': '<p>I would use unsafe code and run the <code>for</code> loop comparing Int32 pointers.</p>\n\n<p>Maybe you should also consider checking the arrays to be non-null.</p>\n'}, {'answer_id': 43303, 'author': 'Markus Olsson', 'author_id': 2114, 'author_profile': 'https://Stackoverflow.com/users/2114', 'pm_score': 1, 'selected': False, 'text': "<p>Sorry, if you're looking for a managed way you're already doing it correctly and to my knowledge there's no built in method in the BCL for doing this.</p>\n\n<p>You should add some initial null checks and then just reuse it as if it where in BCL.</p>\n"}, {'answer_id': 43305, 'author': 'Jason Bunting', 'author_id': 1790, 'author_profile': 'https://Stackoverflow.com/users/1790', 'pm_score': 5, 'selected': False, 'text': '<p>If you are not opposed to doing it, you can import the J# assembly "vjslib.dll" and use its <a href="http://msdn.microsoft.com/en-us/library/aa988508(VS.80).aspx" rel="noreferrer"><strong>Arrays.equals(byte[], byte[]) method</strong></a>...</p>\n\n<p>Don\'t blame me if someone laughs at you though...</p>\n\n<hr>\n\n<p>EDIT: For what little it is worth, I used Reflector to disassemble the code for that, and here is what it looks like:</p>\n\n<pre><code>public static bool equals(sbyte[] a1, sbyte[] a2)\n{\n  if (a1 == a2)\n  {\n    return true;\n  }\n  if ((a1 != null) &amp;&amp; (a2 != null))\n  {\n    if (a1.Length != a2.Length)\n    {\n      return false;\n    }\n    for (int i = 0; i &lt; a1.Length; i++)\n    {\n      if (a1[i] != a2[i])\n      {\n        return false;\n      }\n    }\n    return true;\n  }\n  return false;\n}\n</code></pre>\n'}, {'answer_id': 43310, 'author': 'aku', 'author_id': 1196, 'author_profile': 'https://Stackoverflow.com/users/1196', 'pm_score': 9, 'selected': False, 'text': '<p>You can use <a href="http://msdn.microsoft.com/en-us/library/bb348567.aspx" rel="noreferrer">Enumerable.SequenceEqual</a> method.</p>\n\n<pre><code>using System;\nusing System.Linq;\n...\nvar a1 = new int[] { 1, 2, 3};\nvar a2 = new int[] { 1, 2, 3};\nvar a3 = new int[] { 1, 2, 4};\nvar x = a1.SequenceEqual(a2); // true\nvar y = a1.SequenceEqual(a3); // false\n</code></pre>\n\n<p>If you can\'t use .NET 3.5 for some reason, your method is OK.<br>\nCompiler\\run-time environment will optimize your loop so you don\'t need to worry about performance. </p>\n'}, {'answer_id': 811292, 'author': 'Milan Gardian', 'author_id': 23843, 'author_profile': 'https://Stackoverflow.com/users/23843', 'pm_score': 5, 'selected': False, 'text': '<p>.NET 3.5 and newer have a new public type, <code>System.Data.Linq.Binary</code> that encapsulates <code>byte[]</code>. It implements <code>IEquatable&lt;Binary&gt;</code> that (in effect) compares two byte arrays. Note that <code>System.Data.Linq.Binary</code> also has implicit conversion operator from <code>byte[]</code>.</p>\n\n<p>MSDN documentation:<a href="http://msdn.microsoft.com/en-us/library/system.data.linq.binary(loband).aspx" rel="noreferrer">System.Data.Linq.Binary</a></p>\n\n<p>Reflector decompile of the Equals method:</p>\n\n<pre><code>private bool EqualsTo(Binary binary)\n{\n    if (this != binary)\n    {\n        if (binary == null)\n        {\n            return false;\n        }\n        if (this.bytes.Length != binary.bytes.Length)\n        {\n            return false;\n        }\n        if (this.hashCode != binary.hashCode)\n        {\n            return false;\n        }\n        int index = 0;\n        int length = this.bytes.Length;\n        while (index &lt; length)\n        {\n            if (this.bytes[index] != binary.bytes[index])\n            {\n                return false;\n            }\n            index++;\n        }\n    }\n    return true;\n}\n</code></pre>\n\n<p>Interesting twist is that they only proceed to byte-by-byte comparison loop if hashes of the two Binary objects are the same. This, however, comes at the cost of computing the hash in constructor of <code>Binary</code> objects (by traversing the array with <code>for</code> loop :-) ).</p>\n\n<p>The above implementation means that in the worst case you may have to traverse the arrays three times: first to compute hash of array1, then to compute hash of array2 and finally (because this is the worst case scenario, lengths and hashes equal) to compare bytes in array1 with bytes in array 2.</p>\n\n<p>Overall, even though <code>System.Data.Linq.Binary</code> is built into BCL, I don\'t think it is the fastest way to compare two byte arrays :-|.</p>\n'}, {'answer_id': 1244181, 'author': 'Mirko Klemm', 'author_id': 488454, 'author_profile': 'https://Stackoverflow.com/users/488454', 'pm_score': 2, 'selected': False, 'text': "<p>I thought about block-transfer acceleration methods built into many graphics cards. But then you would have to copy over all the data byte-wise, so this doesn't help you much if you don't want to implement a whole portion of your logic in unmanaged and hardware-dependent code...</p>\n\n<p>Another way of optimization similar to the approach shown above would be to store as much of your data as possible in a long[] rather than a byte[] right from the start, for example if you are reading it sequentially from a binary file, or if you use a memory mapped file, read in data as long[] or single long values. Then, your comparison loop will only need 1/8th of the number of iterations it would have to do for a byte[] containing the same amount of data.\nIt is a matter of when and how often you need to compare vs. when and how often you need to access the data in a byte-by-byte manner, e.g. to use it in an API call as a parameter in a method that expects a byte[]. In the end, you only can tell if you really know the use case...</p>\n"}, {'answer_id': 1252217, 'author': 'Mikael Svenson', 'author_id': 153390, 'author_profile': 'https://Stackoverflow.com/users/153390', 'pm_score': 3, 'selected': False, 'text': '<p>If you look at how .NET does string.Equals, you see that it uses a private method called EqualsHelper which has an "unsafe" pointer implementation. <a href="http://en.wikipedia.org/wiki/.NET_Reflector" rel="nofollow noreferrer">.NET Reflector</a> is your friend to see how things are done internally.</p>\n\n<p>This can be used as a template for byte array comparison which I did an implementation on in blog post <em><a href="http://techmikael.blogspot.com/2009/01/fast-byte-array-comparison-in-c.html" rel="nofollow noreferrer">Fast byte array comparison in C#</a></em>. I also did some rudimentary benchmarks to see when a safe implementation is faster than the unsafe.</p>\n\n<p>That said, unless you really need killer performance, I\'d go for a simple fr loop comparison.</p>\n'}, {'answer_id': 1445280, 'author': 'Kevin Driedger', 'author_id': 9587, 'author_profile': 'https://Stackoverflow.com/users/9587', 'pm_score': 2, 'selected': False, 'text': "<p>For comparing short byte arrays the following is an interesting hack:</p>\n\n<pre><code>if(myByteArray1.Length != myByteArray2.Length) return false;\nif(myByteArray1.Length == 8)\n   return BitConverter.ToInt64(myByteArray1, 0) == BitConverter.ToInt64(myByteArray2, 0); \nelse if(myByteArray.Length == 4)\n   return BitConverter.ToInt32(myByteArray2, 0) == BitConverter.ToInt32(myByteArray2, 0); \n</code></pre>\n\n<p>Then I would probably fall out to the solution listed in the question.</p>\n\n<p>It'd be interesting to do a performance analysis of this code.</p>\n"}, {'answer_id': 1445405, 'author': 'plinth', 'author_id': 20481, 'author_profile': 'https://Stackoverflow.com/users/20481', 'pm_score': 8, 'selected': False, 'text': '<p><a href="http://en.wikipedia.org/wiki/Platform_Invocation_Services" rel="noreferrer">P/Invoke</a> powers activate!</p>\n\n<pre><code>[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]\nstatic extern int memcmp(byte[] b1, byte[] b2, long count);\n\nstatic bool ByteArrayCompare(byte[] b1, byte[] b2)\n{\n    // Validate buffers are the same length.\n    // This also ensures that the count does not exceed the length of either buffer.  \n    return b1.Length == b2.Length &amp;&amp; memcmp(b1, b2, b1.Length) == 0;\n}\n</code></pre>\n'}, {'answer_id': 4617030, 'author': 'user565710', 'author_id': 565710, 'author_profile': 'https://Stackoverflow.com/users/565710', 'pm_score': 4, 'selected': False, 'text': '<pre><code> using System.Linq; //SequenceEqual\n\n byte[] ByteArray1 = null;\n byte[] ByteArray2 = null;\n\n ByteArray1 = MyFunct1();\n ByteArray2 = MyFunct2();\n\n if (ByteArray1.SequenceEqual&lt;byte&gt;(ByteArray2) == true)\n {\n    MessageBox.Show("Match");\n }\n else\n {\n   MessageBox.Show("Don\'t match");\n }\n</code></pre>\n'}, {'answer_id': 8140664, 'author': 'Ohad Schneider', 'author_id': 67824, 'author_profile': 'https://Stackoverflow.com/users/67824', 'pm_score': 7, 'selected': False, 'text': '<p>There\'s a new built-in solution for this in .NET 4 - <a href="http://msdn.microsoft.com/en-us/library/system.collections.istructuralequatable.aspx">IStructuralEquatable</a></p>\n\n<pre><code>static bool ByteArrayCompare(byte[] a1, byte[] a2) \n{\n    return StructuralComparisons.StructuralEqualityComparer.Equals(a1, a2);\n}\n</code></pre>\n'}, {'answer_id': 8808245, 'author': 'Hafthor', 'author_id': 4489, 'author_profile': 'https://Stackoverflow.com/users/4489', 'pm_score': 7, 'selected': True, 'text': "<p>Edit: modern fast way is to use <code>a1.SequenceEquals(a2)</code></p>\n<p>User <em>gil</em> suggested unsafe code which spawned this solution:</p>\n<pre><code>// Copyright (c) 2008-2013 Hafthor Stefansson\n// Distributed under the MIT/X11 software license\n// Ref: http://www.opensource.org/licenses/mit-license.php.\nstatic unsafe bool UnsafeCompare(byte[] a1, byte[] a2) {\n  unchecked {\n    if(a1==a2) return true;\n    if(a1==null || a2==null || a1.Length!=a2.Length)\n      return false;\n    fixed (byte* p1=a1, p2=a2) {\n      byte* x1=p1, x2=p2;\n      int l = a1.Length;\n      for (int i=0; i &lt; l/8; i++, x1+=8, x2+=8)\n        if (*((long*)x1) != *((long*)x2)) return false;\n      if ((l &amp; 4)!=0) { if (*((int*)x1)!=*((int*)x2)) return false; x1+=4; x2+=4; }\n      if ((l &amp; 2)!=0) { if (*((short*)x1)!=*((short*)x2)) return false; x1+=2; x2+=2; }\n      if ((l &amp; 1)!=0) if (*((byte*)x1) != *((byte*)x2)) return false;\n      return true;\n    }\n  }\n}\n</code></pre>\n<p>which does 64-bit based comparison for as much of the array as possible. This kind of counts on the fact that the arrays start qword aligned. It'll work if not qword aligned, just not as fast as if it were.</p>\n<p>It performs about seven timers faster than the simple `for` loop. Using the J# library performed equivalently to the original `for` loop. Using .SequenceEqual runs around seven times slower; I think just because it is using IEnumerator.MoveNext. I imagine LINQ-based solutions being at least that slow or worse.\n"}, {'answer_id': 24529567, 'author': 'Kris Dimitrov', 'author_id': 1024488, 'author_profile': 'https://Stackoverflow.com/users/1024488', 'pm_score': -1, 'selected': False, 'text': '<p>If you are looking for a very fast byte array equality comparer, I suggest you take a look at this STSdb Labs article: <a href="http://stsdb.com/forum/stsdb-4-x/sts-labs/466-byte-array-equality-comparer.html#post1249" rel="nofollow">Byte array equality comparer.</a> It features some of the fastest implementations for byte[] array equality comparing, which are presented, performance tested and summarized.</p>\n\n<p>You can also focus on these implementations:</p>\n\n<p><a href="http://svn.stsdb.com:221/svn/STSdb/STSdb4/STSdb4/General/Comparers/BigEndianByteArrayComparer.cs" rel="nofollow">BigEndianByteArrayComparer</a> - fast byte[] array comparer from left to right (BigEndian)\n<a href="http://svn.stsdb.com:221/svn/STSdb/STSdb4/STSdb4/General/Comparers/BigEndianByteArrayComparer.cs" rel="nofollow">BigEndianByteArrayEqualityComparer</a> - - fast byte[] equality comparer from left to right (BigEndian)\n<a href="http://svn.stsdb.com:221/svn/STSdb/STSdb4/STSdb4/General/Comparers/BigEndianByteArrayEqualityComparer.cs" rel="nofollow">LittleEndianByteArrayComparer</a> - fast byte[] array comparer from right to left (LittleEndian)\n<a href="http://svn.stsdb.com:221/svn/STSdb/STSdb4/STSdb4/General/Comparers/LittleEndianByteArrayEqualityComparer.cs" rel="nofollow">LittleEndianByteArrayEqualityComparer</a> - fast byte[] equality comparer from right to left (LittleEndian)</p>\n'}, {'answer_id': 29831846, 'author': 'API_Base', 'author_id': 4691027, 'author_profile': 'https://Stackoverflow.com/users/4691027', 'pm_score': -1, 'selected': False, 'text': '<p>Use <code>SequenceEquals</code> for this to comparison.</p>\n'}, {'answer_id': 30740076, 'author': 'Alon', 'author_id': 2327376, 'author_profile': 'https://Stackoverflow.com/users/2327376', 'pm_score': -1, 'selected': False, 'text': '<p>The short answer is this:</p>\n\n<pre><code>    public bool Compare(byte[] b1, byte[] b2)\n    {\n        return Encoding.ASCII.GetString(b1) == Encoding.ASCII.GetString(b2);\n    }\n</code></pre>\n\n<p>In such a way you can use the optimized .NET string compare to make a byte array compare without the need to write unsafe code. This is how it is done in the <a href="http://referencesource.microsoft.com/#mscorlib/system/string.cs,11648d2d83718c5e" rel="nofollow">background</a>:</p>\n\n<pre><code>private unsafe static bool EqualsHelper(String strA, String strB)\n{\n    Contract.Requires(strA != null);\n    Contract.Requires(strB != null);\n    Contract.Requires(strA.Length == strB.Length);\n\n    int length = strA.Length;\n\n    fixed (char* ap = &amp;strA.m_firstChar) fixed (char* bp = &amp;strB.m_firstChar)\n    {\n        char* a = ap;\n        char* b = bp;\n\n        // Unroll the loop\n\n        #if AMD64\n            // For the AMD64 bit platform we unroll by 12 and\n            // check three qwords at a time. This is less code\n            // than the 32 bit case and is shorter\n            // pathlength.\n\n            while (length &gt;= 12)\n            {\n                if (*(long*)a     != *(long*)b)     return false;\n                if (*(long*)(a+4) != *(long*)(b+4)) return false;\n                if (*(long*)(a+8) != *(long*)(b+8)) return false;\n                a += 12; b += 12; length -= 12;\n            }\n       #else\n           while (length &gt;= 10)\n           {\n               if (*(int*)a != *(int*)b) return false;\n               if (*(int*)(a+2) != *(int*)(b+2)) return false;\n               if (*(int*)(a+4) != *(int*)(b+4)) return false;\n               if (*(int*)(a+6) != *(int*)(b+6)) return false;\n               if (*(int*)(a+8) != *(int*)(b+8)) return false;\n               a += 10; b += 10; length -= 10;\n           }\n       #endif\n\n        // This depends on the fact that the String objects are\n        // always zero terminated and that the terminating zero is not included\n        // in the length. For odd string sizes, the last compare will include\n        // the zero terminator.\n        while (length &gt; 0)\n        {\n            if (*(int*)a != *(int*)b) break;\n            a += 2; b += 2; length -= 2;\n        }\n\n        return (length &lt;= 0);\n    }\n}\n</code></pre>\n'}, {'answer_id': 33307903, 'author': 'ArekBulski', 'author_id': 2375119, 'author_profile': 'https://Stackoverflow.com/users/2375119', 'pm_score': 5, 'selected': False, 'text': '<p><a href="https://stackoverflow.com/questions/33294580/sse-instruction-to-check-if-byte-array-is-zeroes-c-sharp">I posted</a> a similar question about checking if byte[] is full of zeroes. (SIMD code was beaten so I removed it from this answer.) Here is fastest code from my comparisons:</p>\n\n<pre><code>static unsafe bool EqualBytesLongUnrolled (byte[] data1, byte[] data2)\n{\n    if (data1 == data2)\n        return true;\n    if (data1.Length != data2.Length)\n        return false;\n\n    fixed (byte* bytes1 = data1, bytes2 = data2) {\n        int len = data1.Length;\n        int rem = len % (sizeof(long) * 16);\n        long* b1 = (long*)bytes1;\n        long* b2 = (long*)bytes2;\n        long* e1 = (long*)(bytes1 + len - rem);\n\n        while (b1 &lt; e1) {\n            if (*(b1) != *(b2) || *(b1 + 1) != *(b2 + 1) || \n                *(b1 + 2) != *(b2 + 2) || *(b1 + 3) != *(b2 + 3) ||\n                *(b1 + 4) != *(b2 + 4) || *(b1 + 5) != *(b2 + 5) || \n                *(b1 + 6) != *(b2 + 6) || *(b1 + 7) != *(b2 + 7) ||\n                *(b1 + 8) != *(b2 + 8) || *(b1 + 9) != *(b2 + 9) || \n                *(b1 + 10) != *(b2 + 10) || *(b1 + 11) != *(b2 + 11) ||\n                *(b1 + 12) != *(b2 + 12) || *(b1 + 13) != *(b2 + 13) || \n                *(b1 + 14) != *(b2 + 14) || *(b1 + 15) != *(b2 + 15))\n                return false;\n            b1 += 16;\n            b2 += 16;\n        }\n\n        for (int i = 0; i &lt; rem; i++)\n            if (data1 [len - 1 - i] != data2 [len - 1 - i])\n                return false;\n\n        return true;\n    }\n}\n</code></pre>\n\n<p>Measured on two 256MB byte arrays:</p>\n\n<pre><code>UnsafeCompare                           : 86,8784 ms\nEqualBytesSimd                          : 71,5125 ms\nEqualBytesSimdUnrolled                  : 73,1917 ms\nEqualBytesLongUnrolled                  : 39,8623 ms\n</code></pre>\n'}, {'answer_id': 36291188, 'author': 'Zar Shardan', 'author_id': 913845, 'author_profile': 'https://Stackoverflow.com/users/913845', 'pm_score': 2, 'selected': False, 'text': '<p>Couldn\'t find a solution I\'m completely happy with (reasonable performance, but no unsafe code/pinvoke) so I came up with this, nothing really original, but works:</p>\n\n<pre><code>    /// &lt;summary&gt;\n    /// \n    /// &lt;/summary&gt;\n    /// &lt;param name="array1"&gt;&lt;/param&gt;\n    /// &lt;param name="array2"&gt;&lt;/param&gt;\n    /// &lt;param name="bytesToCompare"&gt; 0 means compare entire arrays&lt;/param&gt;\n    /// &lt;returns&gt;&lt;/returns&gt;\n    public static bool ArraysEqual(byte[] array1, byte[] array2, int bytesToCompare = 0)\n    {\n        if (array1.Length != array2.Length) return false;\n\n        var length = (bytesToCompare == 0) ? array1.Length : bytesToCompare;\n        var tailIdx = length - length % sizeof(Int64);\n\n        //check in 8 byte chunks\n        for (var i = 0; i &lt; tailIdx; i += sizeof(Int64))\n        {\n            if (BitConverter.ToInt64(array1, i) != BitConverter.ToInt64(array2, i)) return false;\n        }\n\n        //check the remainder of the array, always shorter than 8 bytes\n        for (var i = tailIdx; i &lt; length; i++)\n        {\n            if (array1[i] != array2[i]) return false;\n        }\n\n        return true;\n    }\n</code></pre>\n\n<p>Performance compared with some of the other solutions on this page:</p>\n\n<p>Simple Loop: 19837 ticks, 1.00</p>\n\n<p>*BitConverter: 4886 ticks, 4.06</p>\n\n<p>UnsafeCompare: 1636 ticks, 12.12</p>\n\n<p>EqualBytesLongUnrolled: 637 ticks, 31.09</p>\n\n<p>P/Invoke memcmp: 369 ticks, 53.67</p>\n\n<p>Tested in linqpad, 1000000 bytes identical arrays (worst case scenario), 500 iterations each.</p>\n'}, {'answer_id': 38002854, 'author': 'Mr Anderson', 'author_id': 6196648, 'author_profile': 'https://Stackoverflow.com/users/6196648', 'pm_score': 3, 'selected': False, 'text': "<p>I developed a method that slightly beats <code>memcmp()</code> (plinth's answer) and very slighly beats <code>EqualBytesLongUnrolled()</code> (Arek Bulski's answer) on my PC. Basically, it unrolls the loop by 4 instead of 8.</p>\n\n<p><strong>Update 30 Mar. 2019</strong>:</p>\n\n<p>Starting in .NET core 3.0, we have SIMD support!</p>\n\n<p>This solution is fastest by a considerable margin on my PC:</p>\n\n<pre><code>#if NETCOREAPP3_0\nusing System.Runtime.Intrinsics.X86;\n#endif\n…\n\npublic static unsafe bool Compare(byte[] arr0, byte[] arr1)\n{\n    if (arr0 == arr1)\n    {\n        return true;\n    }\n    if (arr0 == null || arr1 == null)\n    {\n        return false;\n    }\n    if (arr0.Length != arr1.Length)\n    {\n        return false;\n    }\n    if (arr0.Length == 0)\n    {\n        return true;\n    }\n    fixed (byte* b0 = arr0, b1 = arr1)\n    {\n#if NETCOREAPP3_0\n        if (Avx2.IsSupported)\n        {\n            return Compare256(b0, b1, arr0.Length);\n        }\n        else if (Sse2.IsSupported)\n        {\n            return Compare128(b0, b1, arr0.Length);\n        }\n        else\n#endif\n        {\n            return Compare64(b0, b1, arr0.Length);\n        }\n    }\n}\n#if NETCOREAPP3_0\npublic static unsafe bool Compare256(byte* b0, byte* b1, int length)\n{\n    byte* lastAddr = b0 + length;\n    byte* lastAddrMinus128 = lastAddr - 128;\n    const int mask = -1;\n    while (b0 &lt; lastAddrMinus128) // unroll the loop so that we are comparing 128 bytes at a time.\n    {\n        if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0), Avx.LoadVector256(b1))) != mask)\n        {\n            return false;\n        }\n        if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0 + 32), Avx.LoadVector256(b1 + 32))) != mask)\n        {\n            return false;\n        }\n        if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0 + 64), Avx.LoadVector256(b1 + 64))) != mask)\n        {\n            return false;\n        }\n        if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0 + 96), Avx.LoadVector256(b1 + 96))) != mask)\n        {\n            return false;\n        }\n        b0 += 128;\n        b1 += 128;\n    }\n    while (b0 &lt; lastAddr)\n    {\n        if (*b0 != *b1) return false;\n        b0++;\n        b1++;\n    }\n    return true;\n}\npublic static unsafe bool Compare128(byte* b0, byte* b1, int length)\n{\n    byte* lastAddr = b0 + length;\n    byte* lastAddrMinus64 = lastAddr - 64;\n    const int mask = 0xFFFF;\n    while (b0 &lt; lastAddrMinus64) // unroll the loop so that we are comparing 64 bytes at a time.\n    {\n        if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0), Sse2.LoadVector128(b1))) != mask)\n        {\n            return false;\n        }\n        if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0 + 16), Sse2.LoadVector128(b1 + 16))) != mask)\n        {\n            return false;\n        }\n        if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0 + 32), Sse2.LoadVector128(b1 + 32))) != mask)\n        {\n            return false;\n        }\n        if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0 + 48), Sse2.LoadVector128(b1 + 48))) != mask)\n        {\n            return false;\n        }\n        b0 += 64;\n        b1 += 64;\n    }\n    while (b0 &lt; lastAddr)\n    {\n        if (*b0 != *b1) return false;\n        b0++;\n        b1++;\n    }\n    return true;\n}\n#endif\npublic static unsafe bool Compare64(byte* b0, byte* b1, int length)\n{\n    byte* lastAddr = b0 + length;\n    byte* lastAddrMinus32 = lastAddr - 32;\n    while (b0 &lt; lastAddrMinus32) // unroll the loop so that we are comparing 32 bytes at a time.\n    {\n        if (*(ulong*)b0 != *(ulong*)b1) return false;\n        if (*(ulong*)(b0 + 8) != *(ulong*)(b1 + 8)) return false;\n        if (*(ulong*)(b0 + 16) != *(ulong*)(b1 + 16)) return false;\n        if (*(ulong*)(b0 + 24) != *(ulong*)(b1 + 24)) return false;\n        b0 += 32;\n        b1 += 32;\n    }\n    while (b0 &lt; lastAddr)\n    {\n        if (*b0 != *b1) return false;\n        b0++;\n        b1++;\n    }\n    return true;\n}\n</code></pre>\n"}, {'answer_id': 39701555, 'author': 'Motlicek Petr', 'author_id': 819843, 'author_profile': 'https://Stackoverflow.com/users/819843', 'pm_score': 2, 'selected': False, 'text': '<p>It seems that <em>EqualBytesLongUnrolled</em> is the best from the above suggested.</p>\n\n<p>Skipped methods (Enumerable.SequenceEqual,StructuralComparisons.StructuralEqualityComparer.Equals),  were not-patient-for-slow. On 265MB arrays I have measured this:</p>\n\n<pre><code>Host Process Environment Information:\nBenchmarkDotNet.Core=v0.9.9.0\nOS=Microsoft Windows NT 6.2.9200.0\nProcessor=Intel(R) Core(TM) i7-3770 CPU 3.40GHz, ProcessorCount=8\nFrequency=3323582 ticks, Resolution=300.8802 ns, Timer=TSC\nCLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]\nGC=Concurrent Workstation\nJitModules=clrjit-v4.6.1590.0\n\nType=CompareMemoriesBenchmarks  Mode=Throughput  \n\n                 Method |      Median |    StdDev | Scaled | Scaled-SD |\n----------------------- |------------ |---------- |------- |---------- |\n             NewMemCopy |  30.0443 ms | 1.1880 ms |   1.00 |      0.00 |\n EqualBytesLongUnrolled |  29.9917 ms | 0.7480 ms |   0.99 |      0.04 |\n          msvcrt_memcmp |  30.0930 ms | 0.2964 ms |   1.00 |      0.03 |\n          UnsafeCompare |  31.0520 ms | 0.7072 ms |   1.03 |      0.04 |\n       ByteArrayCompare | 212.9980 ms | 2.0776 ms |   7.06 |      0.25 |\n</code></pre>\n\n<hr>\n\n<pre><code>OS=Windows\nProcessor=?, ProcessorCount=8\nFrequency=3323582 ticks, Resolution=300.8802 ns, Timer=TSC\nCLR=CORE, Arch=64-bit ? [RyuJIT]\nGC=Concurrent Workstation\ndotnet cli version: 1.0.0-preview2-003131\n\nType=CompareMemoriesBenchmarks  Mode=Throughput  \n\n                 Method |      Median |    StdDev | Scaled | Scaled-SD |\n----------------------- |------------ |---------- |------- |---------- |\n             NewMemCopy |  30.1789 ms | 0.0437 ms |   1.00 |      0.00 |\n EqualBytesLongUnrolled |  30.1985 ms | 0.1782 ms |   1.00 |      0.01 |\n          msvcrt_memcmp |  30.1084 ms | 0.0660 ms |   1.00 |      0.00 |\n          UnsafeCompare |  31.1845 ms | 0.4051 ms |   1.03 |      0.01 |\n       ByteArrayCompare | 212.0213 ms | 0.1694 ms |   7.03 |      0.01 |\n</code></pre>\n'}, {'answer_id': 43191293, 'author': 'Eli Arbel', 'author_id': 276083, 'author_profile': 'https://Stackoverflow.com/users/276083', 'pm_score': 4, 'selected': False, 'text': '<p>Let\'s add one more!</p>\n\n<p>Recently Microsoft released a special NuGet package, <a href="https://www.nuget.org/packages/System.Runtime.CompilerServices.Unsafe" rel="noreferrer">System.Runtime.CompilerServices.Unsafe</a>. It\'s special because it\'s written in <a href="https://github.com/dotnet/corefx/blob/50ec3a52306df5e96d9d90543f8a6941e699b8d3/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il" rel="noreferrer">IL</a>, and provides low-level functionality not directly available in C#.</p>\n\n<p>One of its methods, <code>Unsafe.As&lt;T&gt;(object)</code> allows casting any reference type to another reference type, skipping any safety checks. This is usually a <strong>very</strong> bad idea, but if both types have the same structure, it can work. So we can use this to cast a <code>byte[]</code> to a <code>long[]</code>:</p>\n\n<pre><code>bool CompareWithUnsafeLibrary(byte[] a1, byte[] a2)\n{\n    if (a1.Length != a2.Length) return false;\n\n    var longSize = (int)Math.Floor(a1.Length / 8.0);\n    var long1 = Unsafe.As&lt;long[]&gt;(a1);\n    var long2 = Unsafe.As&lt;long[]&gt;(a2);\n\n    for (var i = 0; i &lt; longSize; i++)\n    {\n        if (long1[i] != long2[i]) return false;\n    }\n\n    for (var i = longSize * 8; i &lt; a1.Length; i++)\n    {\n        if (a1[i] != a2[i]) return false;\n    }\n\n    return true;\n}\n</code></pre>\n\n<p>Note that <code>long1.Length</code> would still return the original array\'s length, since it\'s stored in a field in the array\'s memory structure.</p>\n\n<p>This method is not quite as fast as other methods demonstrated here, but it is a lot faster than the naive method, doesn\'t use unsafe code or P/Invoke or pinning, and the implementation is quite straightforward (IMO). Here are some <a href="http://benchmarkdotnet.org/" rel="noreferrer">BenchmarkDotNet</a> results from my machine:</p>\n\n<pre class="lang-none prettyprint-override"><code>BenchmarkDotNet=v0.10.3.0, OS=Microsoft Windows NT 6.2.9200.0\nProcessor=Intel(R) Core(TM) i7-4870HQ CPU 2.50GHz, ProcessorCount=8\nFrequency=2435775 Hz, Resolution=410.5470 ns, Timer=TSC\n  [Host]     : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0\n  DefaultJob : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0\n\n                 Method |          Mean |    StdDev |\n----------------------- |-------------- |---------- |\n          UnsafeLibrary |   125.8229 ns | 0.3588 ns |\n          UnsafeCompare |    89.9036 ns | 0.8243 ns |\n           JSharpEquals | 1,432.1717 ns | 1.3161 ns |\n EqualBytesLongUnrolled |    43.7863 ns | 0.8923 ns |\n              NewMemCmp |    65.4108 ns | 0.2202 ns |\n            ArraysEqual |   910.8372 ns | 2.6082 ns |\n          PInvokeMemcmp |    52.7201 ns | 0.1105 ns |\n</code></pre>\n\n<p>I\'ve also created a <a href="https://gist.github.com/aelij/b62d149e1a85c3edfad7598e9c2f12cb" rel="noreferrer">gist with all the tests</a>.</p>\n'}, {'answer_id': 46005655, 'author': 'James Curran', 'author_id': 12725, 'author_profile': 'https://Stackoverflow.com/users/12725', 'pm_score': 0, 'selected': False, 'text': '<p>This is almost certainly much slower than any other version given here, but it was fun to write.</p>\n\n<pre><code>static bool ByteArrayEquals(byte[] a1, byte[] a2) \n{\n    return a1.Zip(a2, (l, r) =&gt; l == r).All(x =&gt; x);\n}\n</code></pre>\n'}, {'answer_id': 46471559, 'author': 'John Leidegren', 'author_id': 58961, 'author_profile': 'https://Stackoverflow.com/users/58961', 'pm_score': 3, 'selected': False, 'text': '<p>I did some measurements using attached program .net 4.7 release build without the debugger attached. I think people have been using the wrong metric since what you are about if you care about speed here is how long it takes to figure out if two byte arrays are equal. i.e. throughput in bytes.</p>\n\n<pre><code>StructuralComparison :              4.6 MiB/s\nfor                  :            274.5 MiB/s\nToUInt32             :            263.6 MiB/s\nToUInt64             :            474.9 MiB/s\nmemcmp               :           8500.8 MiB/s\n</code></pre>\n\n<p>As you can see, there\'s no better way than <code>memcmp</code> and it\'s orders of magnitude faster. A simple <code>for</code> loop is the second best option. And it still boggles my mind why Microsoft cannot simply include a <code>Buffer.Compare</code> method.</p>\n\n<p>[Program.cs]:</p>\n\n<pre><code>using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace memcmp\n{\n    class Program\n    {\n        static byte[] TestVector(int size)\n        {\n            var data = new byte[size];\n            using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider())\n            {\n                rng.GetBytes(data);\n            }\n            return data;\n        }\n\n        static TimeSpan Measure(string testCase, TimeSpan offset, Action action, bool ignore = false)\n        {\n            var t = Stopwatch.StartNew();\n            var n = 0L;\n            while (t.Elapsed &lt; TimeSpan.FromSeconds(10))\n            {\n                action();\n                n++;\n            }\n            var elapsed = t.Elapsed - offset;\n            if (!ignore)\n            {\n                Console.WriteLine($"{testCase,-16} : {n / elapsed.TotalSeconds,16:0.0} MiB/s");\n            }\n            return elapsed;\n        }\n\n        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]\n        static extern int memcmp(byte[] b1, byte[] b2, long count);\n\n        static void Main(string[] args)\n        {\n            // how quickly can we establish if two sequences of bytes are equal?\n\n            // note that we are testing the speed of different comparsion methods\n\n            var a = TestVector(1024 * 1024); // 1 MiB\n            var b = (byte[])a.Clone();\n\n            // was meant to offset the overhead of everything but copying but my attempt was a horrible mistake... should have reacted sooner due to the initially ridiculous throughput values...\n            // Measure("offset", new TimeSpan(), () =&gt; { return; }, ignore: true);\n            var offset = TimeZone.Zero\n\n            Measure("StructuralComparison", offset, () =&gt;\n            {\n                StructuralComparisons.StructuralEqualityComparer.Equals(a, b);\n            });\n\n            Measure("for", offset, () =&gt;\n            {\n                for (int i = 0; i &lt; a.Length; i++)\n                {\n                    if (a[i] != b[i]) break;\n                }\n            });\n\n            Measure("ToUInt32", offset, () =&gt;\n            {\n                for (int i = 0; i &lt; a.Length; i += 4)\n                {\n                    if (BitConverter.ToUInt32(a, i) != BitConverter.ToUInt32(b, i)) break;\n                }\n            });\n\n            Measure("ToUInt64", offset, () =&gt;\n            {\n                for (int i = 0; i &lt; a.Length; i += 8)\n                {\n                    if (BitConverter.ToUInt64(a, i) != BitConverter.ToUInt64(b, i)) break;\n                }\n            });\n\n            Measure("memcmp", offset, () =&gt;\n            {\n                memcmp(a, b, a.Length);\n            });\n        }\n    }\n}\n</code></pre>\n'}, {'answer_id': 48577229, 'author': 'Zapnologica', 'author_id': 1331971, 'author_profile': 'https://Stackoverflow.com/users/1331971', 'pm_score': 2, 'selected': False, 'text': '<p>I have not seen many linq solutions here.</p>\n\n<p>I am not sure of the performance implications, however I generally stick to <code>linq</code> as rule of thumb and then optimize later if necessary.</p>\n\n<pre><code>public bool CompareTwoArrays(byte[] array1, byte[] array2)\n {\n   return !array1.Where((t, i) =&gt; t != array2[i]).Any();\n }\n</code></pre>\n\n<p>Please do note this only works if they are the same size arrays.\nan extension could look like so</p>\n\n<pre><code>public bool CompareTwoArrays(byte[] array1, byte[] array2)\n {\n   if (array1.Length != array2.Length) return false;\n   return !array1.Where((t, i) =&gt; t != array2[i]).Any();\n }\n</code></pre>\n'}, {'answer_id': 48599119, 'author': 'Joe Amenta', 'author_id': 1083771, 'author_profile': 'https://Stackoverflow.com/users/1083771', 'pm_score': 7, 'selected': False, 'text': '<p><code>Span&lt;T&gt;</code> offers an extremely competitive alternative without having to throw confusing and/or non-portable fluff into your own application\'s code base:</p>\n<pre class="lang-cs prettyprint-override"><code>// byte[] is implicitly convertible to ReadOnlySpan&lt;byte&gt;\nstatic bool ByteArrayCompare(ReadOnlySpan&lt;byte&gt; a1, ReadOnlySpan&lt;byte&gt; a2)\n{\n    return a1.SequenceEqual(a2);\n}\n</code></pre>\n<p>The (guts of the) implementation as of .NET 6.0.4 can be found <a href="https://github.com/dotnet/runtime/blob/v6.0.4/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs#L1420-L1634" rel="noreferrer">here</a>.</p>\n<p>I\'ve <a href="https://gist.github.com/airbreather/90c5fd3ba9d77fcd7c106db3beeb569b/revisions" rel="noreferrer">revised</a> @EliArbel\'s gist to add this method as <code>SpansEqual</code>, drop most of the less interesting performers in others\' benchmarks, run it with different array sizes, output graphs, and mark <code>SpansEqual</code> as the baseline so that it reports how the different methods compare to <code>SpansEqual</code>.</p>\n<p>The below numbers are from the results, lightly edited to remove &quot;Error&quot; column.</p>\n<pre><code>|        Method |  ByteCount |               Mean |          StdDev | Ratio | RatioSD |\n|-------------- |----------- |-------------------:|----------------:|------:|--------:|\n|    SpansEqual |         15 |           2.074 ns |       0.0233 ns |  1.00 |    0.00 |\n|  LongPointers |         15 |           2.854 ns |       0.0632 ns |  1.38 |    0.03 |\n|      Unrolled |         15 |          12.449 ns |       0.2487 ns |  6.00 |    0.13 |\n| PInvokeMemcmp |         15 |           7.525 ns |       0.1057 ns |  3.63 |    0.06 |\n|               |            |                    |                 |       |         |\n|    SpansEqual |       1026 |          15.629 ns |       0.1712 ns |  1.00 |    0.00 |\n|  LongPointers |       1026 |          46.487 ns |       0.2938 ns |  2.98 |    0.04 |\n|      Unrolled |       1026 |          23.786 ns |       0.1044 ns |  1.52 |    0.02 |\n| PInvokeMemcmp |       1026 |          28.299 ns |       0.2781 ns |  1.81 |    0.03 |\n|               |            |                    |                 |       |         |\n|    SpansEqual |    1048585 |      17,920.329 ns |     153.0750 ns |  1.00 |    0.00 |\n|  LongPointers |    1048585 |      42,077.448 ns |     309.9067 ns |  2.35 |    0.02 |\n|      Unrolled |    1048585 |      29,084.901 ns |     428.8496 ns |  1.62 |    0.03 |\n| PInvokeMemcmp |    1048585 |      30,847.572 ns |     213.3162 ns |  1.72 |    0.02 |\n|               |            |                    |                 |       |         |\n|    SpansEqual | 2147483591 | 124,752,376.667 ns | 552,281.0202 ns |  1.00 |    0.00 |\n|  LongPointers | 2147483591 | 139,477,269.231 ns | 331,458.5429 ns |  1.12 |    0.00 |\n|      Unrolled | 2147483591 | 137,617,423.077 ns | 238,349.5093 ns |  1.10 |    0.00 |\n| PInvokeMemcmp | 2147483591 | 138,373,253.846 ns | 288,447.8278 ns |  1.11 |    0.01 |\n</code></pre>\n<p><s>I was surprised to see <code>SpansEqual</code> not come out on top for the max-array-size methods, but the difference is so minor that I don\'t think it\'ll ever matter.</s>  After refreshing to run on .NET 6.0.4 with my newer hardware, <code>SpansEqual</code> now comfortably outperforms all others at all array sizes.</p>\n<p>My system info:</p>\n<pre><code>BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000\nAMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores\n.NET SDK=6.0.202\n  [Host]     : .NET 6.0.4 (6.0.422.16404), X64 RyuJIT\n  DefaultJob : .NET 6.0.4 (6.0.422.16404), X64 RyuJIT\n</code></pre>\n'}, {'answer_id': 48666556, 'author': 'Raymond Osterbrink', 'author_id': 2576585, 'author_profile': 'https://Stackoverflow.com/users/2576585', 'pm_score': -1, 'selected': False, 'text': "<p>Since many of the fancy solutions above don't work with UWP and because I love Linq and functional approaches I pressent you my version to this problem.\nTo escape the comparison when the first difference occures, I chose .FirstOrDefault()</p>\n\n<pre><code>public static bool CompareByteArrays(byte[] ba0, byte[] ba1) =&gt;\n    !(ba0.Length != ba1.Length || Enumerable.Range(1,ba0.Length)\n        .FirstOrDefault(n =&gt; ba0[n] != ba1[n]) &gt; 0);\n</code></pre>\n"}, {'answer_id': 48975665, 'author': 'Casey Chester', 'author_id': 2726757, 'author_profile': 'https://Stackoverflow.com/users/2726757', 'pm_score': 1, 'selected': False, 'text': "<p>I settled on a solution inspired by the EqualBytesLongUnrolled method posted by ArekBulski with an additional optimization. In my instance, array differences in arrays tend to be near the tail of the arrays. In testing, I found that when this is the case for large arrays, being able to compare array elements in reverse order gives this solution a huge performance gain over the memcmp based solution. Here is that solution:</p>\n\n<pre><code>public enum CompareDirection { Forward, Backward }\n\nprivate static unsafe bool UnsafeEquals(byte[] a, byte[] b, CompareDirection direction = CompareDirection.Forward)\n{\n    // returns when a and b are same array or both null\n    if (a == b) return true;\n\n    // if either is null or different lengths, can't be equal\n    if (a == null || b == null || a.Length != b.Length)\n        return false;\n\n    const int UNROLLED = 16;                // count of longs 'unrolled' in optimization\n    int size = sizeof(long) * UNROLLED;     // 128 bytes (min size for 'unrolled' optimization)\n    int len = a.Length;\n    int n = len / size;         // count of full 128 byte segments\n    int r = len % size;         // count of remaining 'unoptimized' bytes\n\n    // pin the arrays and access them via pointers\n    fixed (byte* pb_a = a, pb_b = b)\n    {\n        if (r &gt; 0 &amp;&amp; direction == CompareDirection.Backward)\n        {\n            byte* pa = pb_a + len - 1;\n            byte* pb = pb_b + len - 1;\n            byte* phead = pb_a + len - r;\n            while(pa &gt;= phead)\n            {\n                if (*pa != *pb) return false;\n                pa--;\n                pb--;\n            }\n        }\n\n        if (n &gt; 0)\n        {\n            int nOffset = n * size;\n            if (direction == CompareDirection.Forward)\n            {\n                long* pa = (long*)pb_a;\n                long* pb = (long*)pb_b;\n                long* ptail = (long*)(pb_a + nOffset);\n                while (pa &lt; ptail)\n                {\n                    if (*(pa + 0) != *(pb + 0) || *(pa + 1) != *(pb + 1) ||\n                        *(pa + 2) != *(pb + 2) || *(pa + 3) != *(pb + 3) ||\n                        *(pa + 4) != *(pb + 4) || *(pa + 5) != *(pb + 5) ||\n                        *(pa + 6) != *(pb + 6) || *(pa + 7) != *(pb + 7) ||\n                        *(pa + 8) != *(pb + 8) || *(pa + 9) != *(pb + 9) ||\n                        *(pa + 10) != *(pb + 10) || *(pa + 11) != *(pb + 11) ||\n                        *(pa + 12) != *(pb + 12) || *(pa + 13) != *(pb + 13) ||\n                        *(pa + 14) != *(pb + 14) || *(pa + 15) != *(pb + 15)\n                    )\n                    {\n                        return false;\n                    }\n                    pa += UNROLLED;\n                    pb += UNROLLED;\n                }\n            }\n            else\n            {\n                long* pa = (long*)(pb_a + nOffset);\n                long* pb = (long*)(pb_b + nOffset);\n                long* phead = (long*)pb_a;\n                while (phead &lt; pa)\n                {\n                    if (*(pa - 1) != *(pb - 1) || *(pa - 2) != *(pb - 2) ||\n                        *(pa - 3) != *(pb - 3) || *(pa - 4) != *(pb - 4) ||\n                        *(pa - 5) != *(pb - 5) || *(pa - 6) != *(pb - 6) ||\n                        *(pa - 7) != *(pb - 7) || *(pa - 8) != *(pb - 8) ||\n                        *(pa - 9) != *(pb - 9) || *(pa - 10) != *(pb - 10) ||\n                        *(pa - 11) != *(pb - 11) || *(pa - 12) != *(pb - 12) ||\n                        *(pa - 13) != *(pb - 13) || *(pa - 14) != *(pb - 14) ||\n                        *(pa - 15) != *(pb - 15) || *(pa - 16) != *(pb - 16)\n                    )\n                    {\n                        return false;\n                    }\n                    pa -= UNROLLED;\n                    pb -= UNROLLED;\n                }\n            }\n        }\n\n        if (r &gt; 0 &amp;&amp; direction == CompareDirection.Forward)\n        {\n            byte* pa = pb_a + len - r;\n            byte* pb = pb_b + len - r;\n            byte* ptail = pb_a + len;\n            while(pa &lt; ptail)\n            {\n                if (*pa != *pb) return false;\n                pa++;\n                pb++;\n            }\n        }\n    }\n\n    return true;\n}\n</code></pre>\n"}, {'answer_id': 56553320, 'author': 'Mahmoud Al-Qudsi', 'author_id': 17027, 'author_profile': 'https://Stackoverflow.com/users/17027', 'pm_score': 3, 'selected': False, 'text': '<p>For those of you that care about order (i.e. want your <code>memcmp</code> to return an <code>int</code> like it should instead of nothing), .NET Core 3.0 (and presumably .NET Standard 2.1 aka .NET 5.0) <a href="https://github.com/dotnet/corefx/pull/26232/files" rel="nofollow noreferrer">will include a <code>Span.SequenceCompareTo(...)</code> extension method</a> (plus a <code>Span.SequenceEqualTo</code>) that can be used to compare two <code>ReadOnlySpan&lt;T&gt;</code> instances (<code>where T: IComparable&lt;T&gt;</code>).</p>\n<p>In <a href="https://github.com/dotnet/corefx/issues/16878" rel="nofollow noreferrer">the original GitHub proposal</a>, the discussion included approach comparisons with jump table calculations, reading a <code>byte[]</code> as <code>long[]</code>, SIMD usage, and p/invoke to the CLR implementation\'s <code>memcmp</code>.</p>\n<p>Going forward, this should be your go-to method for comparing byte arrays or byte ranges (as should using <code>Span&lt;byte&gt;</code> instead of <code>byte[]</code> for your .NET Standard 2.1 APIs), and it is sufficiently fast enough that you should no longer care about optimizing it (and no, despite the similarities in name it does not perform as abysmally as the horrid <code>Enumerable.SequenceEqual</code>).</p>\n<pre><code>#if NETCOREAPP3_0_OR_GREATER\n// Using the platform-native Span&lt;T&gt;.SequenceEqual&lt;T&gt;(..)\npublic static int Compare(byte[] range1, int offset1, byte[] range2, int offset2, int count)\n{\n    var span1 = range1.AsSpan(offset1, count);\n    var span2 = range2.AsSpan(offset2, count);\n\n    return span1.SequenceCompareTo(span2);\n    // or, if you don\'t care about ordering\n    // return span1.SequenceEqual(span2);\n}\n#else\n// The most basic implementation, in platform-agnostic, safe C#\npublic static bool Compare(byte[] range1, int offset1, byte[] range2, int offset2, int count)\n{\n    // Working backwards lets the compiler optimize away bound checking after the first loop\n    for (int i = count - 1; i &gt;= 0; --i)\n    {\n        if (range1[offset1 + i] != range2[offset2 + i])\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n#endif\n</code></pre>\n'}, {'answer_id': 69280107, 'author': 'Antidisestablishmentarianism', 'author_id': 13843929, 'author_profile': 'https://Stackoverflow.com/users/13843929', 'pm_score': 0, 'selected': False, 'text': '<p>This is similar to others, but the difference here is that there is no falling through to the next highest number of bytes I can check at once, e.g. if I have 63 bytes (in my SIMD example) I can check the equality of the first 32 bytes, and then the last 32 bytes, which is faster than checking 32 bytes, 16 bytes, 8 bytes, and so on. The first check you enter is the only check you will need to compare all of the bytes.</p>\n<p>This does come out on top in my tests, but just by a hair.</p>\n<p>The following code is exactly how I tested it in airbreather/ArrayComparePerf.cs.</p>\n<pre><code>public unsafe bool SIMDNoFallThrough()    #requires  System.Runtime.Intrinsics.X86\n{\n    if (a1 == null || a2 == null)\n        return false;\n\n    int length0 = a1.Length;\n\n    if (length0 != a2.Length) return false;\n\n    fixed (byte* b00 = a1, b01 = a2)\n    {\n        byte* b0 = b00, b1 = b01, last0 = b0 + length0, last1 = b1 + length0, last32 = last0 - 31;\n\n        if (length0 &gt; 31)\n        {\n            while (b0 &lt; last32)\n            {\n                if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0), Avx.LoadVector256(b1))) != -1)\n                    return false;\n                b0 += 32;\n                b1 += 32;\n            }\n            return Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(last0 - 32), Avx.LoadVector256(last1 - 32))) == -1;\n        }\n\n        if (length0 &gt; 15)\n        {\n            if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0), Sse2.LoadVector128(b1))) != 65535)\n                return false;\n            return Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(last0 - 16), Sse2.LoadVector128(last1 - 16))) == 65535;\n        }\n\n        if (length0 &gt; 7)\n        {\n            if (*(ulong*)b0 != *(ulong*)b1)\n                return false;\n            return *(ulong*)(last0 - 8) == *(ulong*)(last1 - 8);\n        }\n\n        if (length0 &gt; 3)\n        {\n            if (*(uint*)b0 != *(uint*)b1)\n                return false;\n            return *(uint*)(last0 - 4) == *(uint*)(last1 - 4);\n        }\n\n        if (length0 &gt; 1)\n        {\n            if (*(ushort*)b0 != *(ushort*)b1)\n                return false;\n            return *(ushort*)(last0 - 2) == *(ushort*)(last1 - 2);\n        }\n\n        return *b0 == *b1;\n    }\n}\n</code></pre>\n<p>If no SIMD is preferred, the same method applied to the the existing LongPointers algorithm:</p>\n<pre><code>public unsafe bool LongPointersNoFallThrough()\n{\n    if (a1 == null || a2 == null || a1.Length != a2.Length)\n        return false;\n    fixed (byte* p1 = a1, p2 = a2)\n    {\n        byte* x1 = p1, x2 = p2;\n        int l = a1.Length;\n        if ((l &amp; 8) != 0)\n        {\n            for (int i = 0; i &lt; l / 8; i++, x1 += 8, x2 += 8)\n                if (*(long*)x1 != *(long*)x2) return false;\n            return *(long*)(x1 + (l - 8)) == *(long*)(x2 + (l - 8));\n        }\n        if ((l &amp; 4) != 0)\n        {\n            if (*(int*)x1 != *(int*)x2) return false; x1 += 4; x2 += 4;\n            return *(int*)(x1 + (l - 4)) == *(int*)(x2 + (l - 4));\n        }\n        if ((l &amp; 2) != 0)\n        {\n            if (*(short*)x1 != *(short*)x2) return false; x1 += 2; x2 += 2;\n            return *(short*)(x1 + (l - 2)) == *(short*)(x2 + (l - 2));\n        }\n        return *x1 == *x2;\n    }\n}\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/43289', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/4489/']