首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

.net的一个Bug:Int64与Byte[8]互转的有关问题

2012-09-17 
.net的一个Bug:Int64与Byte[8]互转的问题有一个64位整数:Int64 n 634636512000000000有两种方法可以转

.net的一个Bug:Int64与Byte[8]互转的问题


有一个64位整数值:

   Int64 n = 634636512000000000;

有两种方法可以转为字节流

1:

   byte[] buffer = new byte[8];
   buffer[0] = (byte)n;
   buffer[1] = (byte)(n >> 8);
   buffer[2] = (byte)(n >> 0x10);
   buffer[3] = (byte)(n >> 0x18);
   buffer[4] = (byte)(n >> 0x20);
   buffer[5] = (byte)(n >> 0x28);
   buffer[6] = (byte)(n >> 0x30);
   buffer[7] = (byte)(n >> 0x38);

2:

   byte[] buffer=BitConverter.GetBytes(n);

两个方法得到的buffer内容是一样的。

然后如果再使用buffer向Int64转回的时候问题出现了。

也有两个方法:

1:

uint num = (uint)(((buffer[0] | (buffer[1] << 8)) | (buffer[2] << 0x10)) | (buffer[3] << 0x18));
uint num2 = (uint)(((buffer[4] | (buffer[5] << 8)) | (buffer[6] << 0x10)) | (buffer[7] << 0x18));
Int64 t = (Int64)((num2 << 0x20) | num);

得到的t值是2614029963???

2:

Int64 t = BitConverter.ToInt64(buffer, 0);

得到t的值是634636512000000000,对!

方法1大家可以从.net源码中找到,比如就在BitConvert.ToInt64方法中存在,或System.IO.BinaryReader类的ReadInt64()方法可以得到。比如源码:

BitConvert.ToInt64方法

public static unsafe long ToInt64(byte[] value, int startIndex){    if (value == null)    {        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);    }    if (((ulong) startIndex) >= value.Length)    {        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);    }    if (startIndex > (value.Length - 8))    {        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);    }    fixed (byte* numRef = &(value[startIndex]))    {        if ((startIndex % 8) == 0)        {            return *(((long*) numRef));        }        if (IsLittleEndian)        {            int num = ((numRef[0] | (numRef[1] << 8)) | (numRef[2] << 0x10)) | (numRef[3] << 0x18);            int num2 = ((numRef[4] | (numRef[5] << 8)) | (numRef[6] << 0x10)) | (numRef[7] << 0x18);            return (((long) ((ulong) num)) | (num2 << 0x20));        }        int num3 = (((numRef[0] << 0x18) | (numRef[1] << 0x10)) | (numRef[2] << 8)) | numRef[3];        int num4 = (((numRef[4] << 0x18) | (numRef[5] << 0x10)) | (numRef[6] << 8)) | numRef[7];        return (((long) ((ulong) num4)) | (num3 << 0x20));    }}

 

 System.IO.BinaryReader.ReadInt64()方法

public virtual long ReadInt64(){    this.FillBuffer(8);    uint num = (uint) (((this.m_buffer[0] | (this.m_buffer[1] << 8)) | (this.m_buffer[2] << 0x10)) | (this.m_buffer[3] << 0x18));    uint num2 = (uint) (((this.m_buffer[4] | (this.m_buffer[5] << 8)) | (this.m_buffer[6] << 0x10)) | (this.m_buffer[7] << 0x18));    return (long) ((num2 << 0x20) | num);}

 

但是,.net里面的源代码错了!!!

哪里错了呢,其实思路是对的,在数量的值小于一个整数的时候也是对的。

问题就出在了最后一个return上。

本来num2应该左移0x20个位,然后成为64位数的高32位,然而这里的num2却是一个uint类型。UInt类型左移后出现的结果仍然是一个UInt的值。

两个UInt的值或(|)后仍是一个UInt,哪里是long呢?

微软在这里犯了一个错误,因为本来正确的代码应该是这样的:

public virtual long ReadInt64(){this.FillBuffer(8);uint num = (uint)(((this.m_buffer[0] | (this.m_buffer[1] << 8)) | (this.m_buffer[2] << 0x10)) | (this.m_buffer[3] << 0x18));uint num2 = (uint)(((this.m_buffer[4] | (this.m_buffer[5] << 8)) | (this.m_buffer[6] << 0x10)) | (this.m_buffer[7] << 0x18));return (((long)num2 << 0x20) | num);}

(long)的位置放错了,或者说,没注意到num2应该使用(Long)转换一下。这是导致错误的原因。

 那为什么BitConvert.ToInt64是对的呢,嘿嘿,因为在本文中它走了if ((startIndex %8) ==0)这个分支,没有走下面的代码。

热点排行