本文介绍了可变长度的两个对int64的补充的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在尝试编写一个GO程序来解析ans.1 BER 2的补码整数编码。但是,该整数可以采用1、2、3或4字节长度编码(取决于其大小)。
根据规范(http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf),最左边的位始终是补码。
执行此操作的干净方法是什么?
func ParseInt(b []byte) (int64, error) {
switch len(b) {
case 1:
// this works
return int64(b[0]&0x7f) - int64(b[0]&0x80), nil
case 2:
// left most byte of b[0] is -32768
case 3:
// left most byte of b[0] is -8388608
case 4:
// left most byte of b[0] is -2147483648 (and so on for 5, 6, 7, 8)
case 5:
case 6:
case 7:
case 8:
default:
return 0, errors.New("value does not fit in a int64")
}
}
ParseInt([]byte{0xfe}) // should return (-2, nil)
ParseInt([]byte{0xfe, 0xff}) // should return (-257, nil)
ParseInt([]byte{0x01, 0x00}) // should return (256, nil)
推荐答案
如果从末尾读取字节,则更容易理解:
- 您不必移动最后一个字节
- 最后一个字节左移8位(一个字节8位)
- 左移倒数第二个字节16
- ...
- 并且从第一个字节只使用7位开始,最左边的位是特殊的。
第一个字节的最左边的位b[0]&080
告诉您是否必须向结果添加偏移量。要选择性添加的偏移量是-1
乘以您输入的数字,即0
,即-1 * (1 << (len(b)*8 - 1)) = 0x80 << (len(b)*8 - 8)
。
个例子。如果输入为...
- 1字节:
int64(b[0]&0x7f) - int64(b[0]&0x80)
- 2字节:
int64(b[0]&0x7f)<<8 + int64(b[1]) - int64(b[0]&0x80)<<8
- 3个字节:
int64(b[0]&0x7f)<<16 + int64(b[1])<<8 + int64(b[2]) - int64(b[0]&0x80)<<16
所有这些案例都可以用一个很好的循环来覆盖。
这里有一个紧凑的实现(在Go Playground上试用):
func ParseInt(b []byte) (int64, error) {
if len(b) > 8 {
return 0, errors.New("value does not fit in a int64")
}
var n int64
for i, v := range b {
shift := uint((len(b) - i - 1) * 8)
if i == 0 && v&0x80 != 0 {
n -= 0x80 << shift
v &= 0x7f
}
n += int64(v) << shift
}
return n, nil
}
这篇关于可变长度的两个对int64的补充的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!