【问题标题】:C# int to byte[]C# int 到字节[]
【发布时间】:2010-11-22 01:56:06
【问题描述】:

我需要将int 转换为byte[] 一种方法是使用BitConverter.GetBytes()。但我不确定这是否符合以下规范:

一个 XDR 有符号整数是一个 32 位数据,它编码一个整数 范围 [-2147483648,2147483647]。整数表示为 二进制补码表示法。最高和最低有效字节是 分别为 0 和 3。整数声明如下:

来源:RFC1014 3.2

如何进行满足上述规范的 int 到字节转换?

【问题讨论】:

  • 这是个好问题。

标签: c# .net bit-manipulation nfs


【解决方案1】:

RFC 只是想说一个有符号整数是一个普通的 4 字节整数,字节以大端方式排序。

现在,您很可能正在使用 little-endian 机器,BitConverter.GetBytes() 将为您提供相反的 byte[]。所以你可以试试:

int intValue;
byte[] intBytes = BitConverter.GetBytes(intValue);
Array.Reverse(intBytes);
byte[] result = intBytes;

但是,为了使代码具有最大的可移植性,您可以这样做:

int intValue;
byte[] intBytes = BitConverter.GetBytes(intValue);
if (BitConverter.IsLittleEndian)
    Array.Reverse(intBytes);
byte[] result = intBytes;

【讨论】:

  • 或者使用ToArray。 byte[] 结果 = BitConverter.GetBytes(intValue).Reverse().ToArray();
  • 为什么最后一行 byte[] result = intBytes;intBytes 不是已经是你想要的数组了吗?
  • @derHugo 没错,result 在这段代码中是多余的。然而,我觉得明确地向读者展示结果是什么比假设他们可以弄清楚结果包含在某个名为intBytes 的变量中更具教学性。此外,分配很便宜,因为它不复制内存也不分配新内存,它只是为已经分配的数组添加一个新名称。那么为什么不这样做呢?
【解决方案2】:

BitConverter.GetBytes(int) 几乎可以做你想做的事,除了字节序错误。

在使用BitConverter.GetBytes 或使用Jon Skeet 的EndianBitConverter class 之前,您可以使用IPAddress.HostToNetwork 方法交换整数值内的字节。这两种方法在可移植性方面都做了正确的事情(tm)。

int value;
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value));

【讨论】:

    【解决方案3】:

    当我看到这个描述时,我有一种感觉,这个 xdr 整数只是一个大端“标准”整数,但它以最模糊的方式表示。 Two's complement notation 更好地称为 U2,它是我们在当今处理器上使用的。字节顺序表明它是big-endian 表示法。
    因此,回答您的问题时,您应该反转数组中的元素 (0 3, 1 2),因为它们是以小端序编码的。只是为了确保,您应该首先检查 BitConverter.IsLittleEndian 以查看您在哪台机器上运行。

    【讨论】:

      【解决方案4】:

      如果您想了解有关表示数字的各种方法(包括补码)的更多一般信息,请查看:

      Two's ComplementSigned Number Representation 在维基百科上

      【讨论】:

        【解决方案5】:

        这是另一种方法:众所周知,1x 字节 = 8x 位,而且“常规”整数 (int32) 包含 32 位(4 字节)。我们可以使用 >> 运算符来右移位(>> 运算符不会改变值。)

        int intValue = 566;
        
        byte[] bytes = new byte[4];
        
        bytes[0] = (byte)(intValue >> 24);
        bytes[1] = (byte)(intValue >> 16);
        bytes[2] = (byte)(intValue >> 8);
        bytes[3] = (byte)intValue;
        
        Console.WriteLine("{0} breaks down to : {1} {2} {3} {4}",
            intValue, bytes[0], bytes[1], bytes[2], bytes[3]);
        

        【讨论】:

        • 不需要数组初始化器和异或 (^) 和 & 0xFF 位。
        • 它是大端的,所以首先存储MSB,所以你应该反转你的索引。
        • 我们可以添加一个相反的例子吗? (字节返回整数)
        • 我使用这个是因为性能。如果我不在乎这个 small 差异,我会选择接受的答案。
        • 您应该将该代码包装在 unchecked 块中。目前它仅在编译器设置中禁用整数溢出检查时才有效。
        【解决方案6】:
        byte[] Take_Byte_Arr_From_Int(Int64 Source_Num)
        {
           Int64 Int64_Num = Source_Num;
           byte Byte_Num;
           byte[] Byte_Arr = new byte[8];
           for (int i = 0; i < 8; i++)
           {
              if (Source_Num > 255)
              {
                 Int64_Num = Source_Num / 256;
                 Byte_Num = (byte)(Source_Num - Int64_Num * 256);
              }
              else
              {
                 Byte_Num = (byte)Int64_Num;
                 Int64_Num = 0;
              }
              Byte_Arr[i] = Byte_Num;
              Source_Num = Int64_Num;
           }
           return (Byte_Arr);
        }
        

        【讨论】:

        • 请补充说明
        • 感谢您的回答,您为什么选择编写新的实现而不是使用 stackoverflow.com/a/1318948/58553 ? (您的解决方案有什么优点或缺点)
        • 如果项目不仅需要使用一种语言开发,在必须实现相同想法的情况下,实现语言之间的代码相似性会很有用。这种方式可能有助于捕捉错误。确保使用‘c#’函数‘BitConverter.GetBytes’和‘Endian’检查大多数情况下需要的所有内容。而且,在某些情况下,可能会发生使用转换,不仅可以转换为 Int32(4 字节)或 Int64(8 字节),还可以转换为其他字节数。谢谢。
        • 这根本不是真正普遍可用的......它总是返回一个 8 字节数组,这带来了很多额外的工作,输入值不是 64 位整数。在转换 Int16 时,我在逻辑上想要一个 2 字节数组。
        【解决方案7】:

        为什么上面示例中的所有这些代码...

        具有显式布局的结构可以双向使用,不会影响性能。

        更新:由于有一个关于如何处理字节序的问题,我添加了一个接口来说明如何抽象它。另一个实现结构可以处理相反的情况

        public interface IIntToByte
        {
            Int32 Int { get; set;}
        
            byte B0 { get; }
            byte B1 { get; }
            byte B2 { get; }
            byte B3 { get; }
        }
        
        [StructLayout(LayoutKind.Explicit)]
        public struct IntToByteLE : UserQuery.IIntToByte
        {
            [FieldOffset(0)]
            public Int32 IntVal;
        
            [FieldOffset(0)]
            public byte b0;
            [FieldOffset(1)]
            public byte b1;
            [FieldOffset(2)]
            public byte b2;
            [FieldOffset(3)]
            public byte b3;
        
            public Int32 Int {
                get{ return IntVal; }
                set{ IntVal = value;}
            }
        
            public byte B0 => b0;
            public byte B1 => b1;
            public byte B2 => b2;
            public byte B3 => b3; 
        }
        

        【讨论】:

        • 你会如何使用这个?其次,即使您在“big-endian”和“little-endian”上运行它,您是否会得到相同的结果。
        • @Peter 这里有更新。它仍然应该比班次表现更好
        • 是的。基本上是作为 c# 结构实现的 c++ 联合。这是超快的,适用于打包和解包各种不适合 bitconverter/endian 问题解决方案的东西。 IIRC,NAudio 使用这种方法效果非常好。
        • 这是最好的答案,有点遗憾,这不是顶级的,只是告诉你一些关于 2019 年编程状态的事情
        【解决方案8】:
        using static System.Console;
        
        namespace IntToBits
        {
            class Program
            {
                static void Main()
                {
                    while (true)
                    {
                        string s = Console.ReadLine();
                        Clear();
                        uint i;
                        bool b = UInt32.TryParse(s, out i);
                        if (b) IntPrinter(i);
                    }
                }
        
                static void IntPrinter(uint i)
                {
                    int[] iarr = new int [32];
                    Write("[");
                    for (int j = 0; j < 32; j++)
                    {
                        uint tmp = i & (uint)Math.Pow(2, j);
        
                        iarr[j] = (int)(tmp >> j);
                    }
                    for (int j = 32; j > 0; j--)
                    {
                        if(j%8==0 && j != 32)Write("|");
                        if(j%4==0 && j%8 !=0) Write("'");
                        Write(iarr[j-1]);
                    }
                    WriteLine("]");
                }
            }
        }```
        

        【讨论】:

          【解决方案9】:

          另一种方法是像这样使用BinaryPrimitives

          byte[] intBytes = BitConverter.GetBytes(123); int actual = BinaryPrimitives.ReadInt32LittleEndian(intBytes);

          【讨论】:

          猜你喜欢
          • 2011-07-31
          • 2016-04-05
          • 1970-01-01
          • 2011-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多