【问题标题】:Int to byte arrayInt 到字节数组
【发布时间】:2010-11-14 07:57:47
【问题描述】:

我认为.net 有某种简单的转换方法可用于将 int 转换为字节数组?我进行了快速搜索,所有解决方案都是一次位屏蔽/移动一个字节,例如“美好的日子”。 某处没有 ToByteArray() 方法吗?

【问题讨论】:

    标签: c# .net bytearray int32


    【解决方案1】:

    2020 年更新 - BinaryPrimitives 现在应该优先于 BitConverter。它提供特定于字节序的 API,并且分配较少。


    byte[] bytes = BitConverter.GetBytes(i);
    

    尽管还请注意,您可能想查看BitConverter.IsLittleEndian,看看会出现哪种情况!

    请注意,如果您重复执行此操作,您可能希望通过移位操作 (>> / <<) 自己编写它来避免所有这些短暂的数组分配,或者通过使用unsafe 代码。移位操作具有不受平台字节序影响的优点;你总是按照你期望的顺序获取字节。

    【讨论】:

    • +1:为清楚起见,我会将“[...] in the order you expect them”替换为“big-endian”。
    • 为什么BitConverter.GetBytes(250) 返回[250,0,0,0],而不是[250]Byte.MaxValue == 255,对吧?
    • @Tobi 因为你正在调用 GetBytes(int) - 所以:4 个字节,你的 CPU 是小端的。 GetBytes(字节)方法没有任何用途。
    • @Tobi re GetBytes(256):你没有得到 255,1 因为它明确地是固定宽度表示 - 字节。您将得到 256 的 little-endian(您的 CPU)固定宽度 32 位表示
    • @Timeless 通常unsafe - 但它会因确切您正在做的事情而有所不同 - 最好的办法是实施两次并测试 1000 万左右,计时
    【解决方案2】:

    马克的答案当然是正确的答案。但是由于他提到了移位运算符和不安全的代码作为替代方案。我想分享一个不太常见的替代方案。使用带有Explicit 布局的结构。这在原理上类似于 C/C++ union

    这是一个结构示例,可用于获取 Int32 数据类型的组件字节,好处是它有两种方式,您可以操作字节值并查看对 Int 的影响。

      using System.Runtime.InteropServices;
    
      [StructLayout(LayoutKind.Explicit)]
      struct Int32Converter
      {
        [FieldOffset(0)] public int Value;
        [FieldOffset(0)] public byte Byte1;
        [FieldOffset(1)] public byte Byte2;
        [FieldOffset(2)] public byte Byte3;
        [FieldOffset(3)] public byte Byte4;
    
        public Int32Converter(int value)
        {
          Byte1 = Byte2 = Byte3 = Byte4 = 0;
          Value = value;
        }
    
        public static implicit operator Int32(Int32Converter value)
        {
          return value.Value;
        }
    
        public static implicit operator Int32Converter(int value)
        {
          return new Int32Converter(value);
        }
      }
    

    上面现在可以如下使用

     Int32Converter i32 = 256;
     Console.WriteLine(i32.Byte1);
     Console.WriteLine(i32.Byte2);
     Console.WriteLine(i32.Byte3);
     Console.WriteLine(i32.Byte4);
    
     i32.Byte2 = 2;
     Console.WriteLine(i32.Value);
    

    当然,不变性警察可能不会对最后的可能性感到兴奋:)

    【讨论】:

    • +1:这是一个不错的方法。如果您担心不可变政策,您可以将字段设为私有并使用 get-only 属性公开它们。
    • @Ani,谢谢,将byte 成员设为私有并创建仅获取属性是个好主意。
    • 语句'Byte1 = Byte2 = Byte3 = Byte4 = 0;'是多余的,因为随后的值分配会覆盖它们。这正是使编译器优化器编写者发疯的那种别名。联合是优雅的,因为它通过内存通道将多个写入折叠到一个单一的。使用 struct 还可以避免非常频繁的情况下的数组分配。
    • @Pekka,编译器强制您初始化结构的所有成员,它没有考虑字节被 int 覆盖的事实,这就是为什么需要初始化,冗余但需要.
    • @Chris,没错,正是优化器警察与别名作斗争。
    【解决方案3】:

    这可能是 OT,但如果您要序列化许多原始类型或 POD 结构,Google Protocol Buffers for .Net 可能对您有用。这解决了@Marc 上面提出的字节顺序问题以及其他有用的功能。

    【讨论】:

      【解决方案4】:

      如果您从 Google 来到这里

      对较早问题的替代答案是指 John Skeet 的库,该库提供的工具可让您将原始数据类型直接写入具有索引偏移量的 byte[]。如果你需要性能的话,比BitConverter 好得多。

      Older thread discussing this issue here

      John Skeet's Libraries are here

      只需下载源代码并查看MiscUtil.Conversion 命名空间。 EndianBitConverter.cs 为您处理一切。

      【讨论】:

        【解决方案5】:

        这里的大多数答案要么是“不安全”,要么不是 LittleEndian 安全的。BitConverter 不是 LittleEndian 安全的。 因此,以here 中的示例为基础(请参阅 PZahra 的帖子),当 BitConverter.IsLittleEndian == true 时,我只需通过反向读取字节数组来制作 LittleEndian 安全版本

        void Main(){    
            Console.WriteLine(BitConverter.IsLittleEndian); 
            byte[] bytes = BitConverter.GetBytes(0xdcbaabcdfffe1608);
            //Console.WriteLine(bytes); 
            string hexStr = ByteArrayToHex(bytes);
            Console.WriteLine(hexStr);
        }
        
        public static string ByteArrayToHex(byte[] data) 
        { 
           char[] c = new char[data.Length * 2]; 
           byte b; 
          if(BitConverter.IsLittleEndian)
          {
                //read the byte array in reverse
                for (int y = data.Length -1, x = 0; y >= 0; --y, ++x) 
                { 
                    b = ((byte)(data[y] >> 4)); 
                    c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
                    b = ((byte)(data[y] & 0xF)); 
                    c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
                }               
            }
            else
            {
                for (int y = 0, x = 0; y < data.Length; ++y, ++x) 
                { 
                    b = ((byte)(data[y] >> 4)); 
                    c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
                    b = ((byte)(data[y] & 0xF)); 
                    c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
                }
            }
            return String.Concat("0x",new string(c));
        }
        

        它返回这个:

        True
        0xDCBAABCDFFFE1608
        

        这是进入字节数组的确切十六进制。

        【讨论】:

        • 它不是从 int 开始的。更不用说,对 read 进行字节顺序检查更合乎逻辑,因此您可以确定数组中的数据是什么样的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-31
        • 2016-04-05
        • 2012-08-12
        • 1970-01-01
        • 1970-01-01
        • 2015-02-15
        相关资源
        最近更新 更多