int64 的可变长度二进制补码

Posted

技术标签:

【中文标题】int64 的可变长度二进制补码【英文标题】:Variable length two's complement to int64 【发布时间】:2021-11-01 09:45:42 【问题描述】:

我正在尝试编写一个 Go 程序来解析 ans.1 BER 二进制补码整数编码。但是,整数可以有 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([]byte0xfe)       // should return (-2, nil)
ParseInt([]byte0xfe, 0xff) // should return (-257, nil)
ParseInt([]byte0x01, 0x00) // should return (256, nil)

【问题讨论】:

如果您从规范中引用准确的解析规则,那将是一个很大的帮助。理想情况下,将// how do I handle this? 替换为// get the lower byte, ... 【参考方案1】:

如果你从末尾读取字节更容易理解:

您不必移动最后一个字节 将最后一个字节左移 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

【讨论】:

太棒了,谢谢!。是 n -= 0x80 &lt;&lt; shift 真的让我大跌眼镜

以上是关于int64 的可变长度二进制补码的主要内容,如果未能解决你的问题,请参考以下文章

关于原码,反码和补码

原始数据类型

求byte b = 200的计算结果

标识符,进制转化,原反补码等

Java数据类型

输出二进制补码