在C#中将int转换为4字节的最快方法

Mic*_*elT 18 .net c# bit-manipulation

在C#中将int转换为4字节的最快方法是什么?

执行时间最快而不是开发时间.

我自己的解决方案是这个代码:

byte[] bytes = new byte[4];
unchecked
{
 bytes[0] = (byte)(data >> 24);
 bytes[1] = (byte)(data >> 16);
 bytes[2] = (byte)(data >> 8);
 bytes[3] = (byte)(data);
}
Run Code Online (Sandbox Code Playgroud)

现在我看到我的解决方案优于两者structBitConverter几个滴答.

我认为不安全可能是最快的选择,并接受这个作为答案,但我更喜欢使用托管选项.

Dar*_*rov 16

在C#中将int转换为4字节的最快方法是什么?

使用BitConverter,它的GetBytes重载采用32位整数:

int i = 123;
byte[] buffer = BitConverter.GetBytes(i);
Run Code Online (Sandbox Code Playgroud)

  • @TomTom,有趣的解决方案.但如果速度相似,我更喜欢BCL方法调用,它也更短,更不容易出错.您不需要将程序集标记为不安全,因为BitConverter.GetBytes是BCL方法.我同意,这是不安全的.我们一直在使用的BCL中有很多不安全的方法. (3认同)
  • @TomTom,好的,我不会和你争论.你不会让我改变主意,也不会让你改变主意.所以我不想继续讨论,因为它对我来说毫无意义.我暴露了我的解决方案,你暴露了你的解决方案,我尊重你的解决方案.这就是为什么Stack Overflow是一个很棒的地方.因为我们可以看到解决问题的不同方法.我认为社区只能从这种多样性中受益. (2认同)
  • 您的解决方案没有考虑到您通常需要写入现有数组。在这种情况下,BitConverter 会慢得多,因为您必须创建一个新数组然后复制它。请看我的回答,我对不同的方法做了比较。 (2认同)

Han*_*ant 15

使用不安全代码的字节*转换是迄今为止最快的:

    unsafe static void Main(string[] args) {
        int i = 0x12345678;
        byte* pi = (byte*)&i;
        byte lsb = pi[0];  
        // etc..
    }
Run Code Online (Sandbox Code Playgroud)

这就是BitConverter所做的,这段代码避免了创建数组的成本.

  • 是的,这就是它使用*unsafe*关键字的原因.哪个可以做到这一点,编写快速代码.OP的请求是*fast*,而不是*类似*. (6认同)
  • 我不得不猜你不适合微软.包含结构的方法的问题在于它们没有内联.至少BitConverter.GetBytes()被内联. (3认同)
  • 使用`unsafe`是完全安全的,只要你可以在可信任的上下文中运行,并且只要有一些方法可以表明如果不仔细检查它可能是不安全的.就像在代码附近的某个地方使用"不安全"一词作为一种指标. (2认同)

Ily*_*dik 10

我已经研究了将基本类型序列化为字节数组所需的时间.当你已经有一个数组和偏移量来放置你的数据时,我就这样做了.我猜这是一个非常重要的案例,与理论相比,得到一个4字节的数组,因为当你序列化某些东西时,它正是你所需要的.我已经发现什么方法的答案更快取决于你想要序列化的类型.我尝试过几种方法:

  1. 带有额外缓冲区溢出检查的不安全引用
  2. GetBytes +结果Buffer.BulkCopy(这与1加上开销基本相同)
  3. 直接分配班次( m_Bytes[offset] = (byte)(value >> 8)
  4. 使用shift和bitwise&直接分配 m_Bytes[offset] = (byte)((i >> 8) & 0xFF)

我跑了所有的测试10毫升.以下是以毫秒为单位的结果

      Long   Int   Short  Byte   Float   Double
1     29     32     31     30     29      34
2     209    233    220    212    208     228
3     63     24     13     8      24      44
4     72     29     14          

正如您所看到的那样,对于long和double,不安全的方式要快得多(无符号版本与其签名版本大致相同,因此它们不在表中).对于short/int/float,最快的方法是使用shift进行2/4/4分配.对于字节,最快的显然是简单的赋值.所以关于原始问题 - 分配方式是最好的.这是以最快的方式执行此类功能的示例:

    public static void WriteInt(byte[] buffer, int offset, int value)
    {
        m_BytesInt[offset] = (byte)(value >> 24);
        m_BytesInt[offset + 1] = (byte)(value >> 16);
        m_BytesInt[offset + 2] = (byte)(value >> 8);
        m_BytesInt[offset + 3] = (byte) value;
    }
Run Code Online (Sandbox Code Playgroud)

PS测试在x64环境下运行,代码在发布模式下编译为cpu any(运行时为x64).


小智 9

最快的方法是使用包含4个字节的结构.

  • 在定义的布局中(在字节位置0,1,2,3
  • 以及从位置0开始的int32.
  • 输入4个变量,读出字节.
  • 成品.

明显快于BitConverter.

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx

有必要的属性.

[StructLayout(LayoutKind.Explicit)]
struct FooUnion
{
    [FieldOffset(0)]
    public byte byte0;
    [FieldOffset(1)]
    public byte byte1;
    [FieldOffset(2)]
    public byte byte2;
    [FieldOffset(3)]
    public byte byte3;

    [FieldOffset(0)]
    public int integer;

}
Run Code Online (Sandbox Code Playgroud)


Geo*_*ett 7

请注意,BitConverter可能不是最快的,如下面的测试所示.

使用BitConverter该类,特别GetBytes是带Int32参数的方法:

var myInt = 123;
var bytes = BitConverter.GetBytes(myInt);
Run Code Online (Sandbox Code Playgroud)

您可以使用它BitConverter.IsLittlEndian来确定基于CPU架构的字节顺序.


编辑:由于编译器优化,下面的测试不是决定性的.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    [StructLayout(LayoutKind.Explicit)]
    struct FooUnion
    {
        [FieldOffset(0)]
        public byte byte0;
        [FieldOffset(1)]
        public byte byte1;
        [FieldOffset(2)]
        public byte byte2;
        [FieldOffset(3)]
        public byte byte3;

        [FieldOffset(0)]
        public int integer;
    }
    class Program
    {
        static void Main(string[] args)
        {
            testUnion();
            testBitConverter();

            Stopwatch Timer = new Stopwatch();

            Timer.Start();
            testUnion();
            Timer.Stop();

            Console.WriteLine(Timer.ElapsedTicks);

            Timer = new Stopwatch();

            Timer.Start();
            testBitConverter();
            Timer.Stop();

            Console.WriteLine(Timer.ElapsedTicks);
            Console.ReadKey();
        }

        static void testBitConverter()
        {
            byte[] UnionBytes;

            for (int i = 0; i < 10000; i++)
            {
                UnionBytes = BitConverter.GetBytes(i);
            }
        }

        static void testUnion()
        {
            byte[] UnionBytes;

            for (int i = 0; i < 10000; i++)
            {
                FooUnion union = new FooUnion() { integer = i };

                UnionBytes = new byte[] { union.byte0, union.byte1, union.byte2, union.byte3 };

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)