将long类型转换为byte数组用于高效传输时的代码问题
4字节存储long值的序列化代码错误分析
我正在创建一种序列化格式,头部使用4个固定字节存储消息体长度,希望用这4个字节存储尽可能大的数值,需要将long类型存入byte[](采用base256编码方式)。以下是我的代码:
long val = 25484394; var encoded = new byte[4]; var max = 0L; for (var i = 0; i < encoded.Length; ++i) { max += (long)Math.Pow((int)byte.MaxValue, i); } if (val >= max) throw new ArgumentOutOfRangeException("value", $"{val} is too large to be encoded (max value is {max})"); for (var i = encoded.Length - 1; i > 0; i--) { //This line is wrong encoded[i] = (byte)(int)Math.Floor(val / Math.Pow(byte.MaxValue, i)); }
这段代码存在以下关键错误:
最大值计算错误:
byte.MaxValue是255,4字节无符号整数能存储的最大值应为2^32 - 1(即4294967295),因为每个字节可表示0-255的数值,4字节组合范围是0到0xFFFFFFFF。但当前代码通过累加255^i计算max,得到的结果仅为1 + 255 + 255² + 255³ = 16581375,远小于实际可存储的最大值,会导致大量合法数值被误判为超出范围。循环遗漏关键字节:
编码循环的条件是i > 0,仅处理了索引3、2、1的字节,完全漏掉了索引0的字节,最终encoded[0]会保持默认值0,导致原始数值的部分信息丢失,解码时无法还原正确值。编码逻辑的精度与逻辑错误:
- 使用
Math.Pow进行浮点数运算会引入精度误差,当数值较大时,浮点数精度损失会导致计算结果不准确,进而造成编码后的字节值错误。 - 每次计算都使用原始的
val值,没有在提取当前字节后更新val,导致所有字节都基于原始值计算,完全不符合base256编码的逻辑——正确逻辑应该是提取当前字节后,将val更新为剩余的数值。
- 使用
修正示例(大端模式)
推荐用整数位运算替代浮点数运算,避免精度问题,同时覆盖所有字节:
long val = 25484394; var encoded = new byte[4]; const long maxValue = 0xFFFFFFFFL; if (val < 0 || val > maxValue) throw new ArgumentOutOfRangeException("value", $"{val} is out of range (max is {maxValue})"); encoded[0] = (byte)(val >> 24); encoded[1] = (byte)(val >> 16); encoded[2] = (byte)(val >> 8); encoded[3] = (byte)val;
内容的提问来源于stack exchange,提问作者Ian Newson
相关产品推荐
相关产品推荐

