如何在 Go 中对字节数组进行左移一位(跨字节进位)

2次阅读

如何在 Go 中对字节数组进行左移一位(跨字节进位)

本文详解如何在 go 中实现字节数组的逻辑左移一位操作,确保高位进位正确传递到下一个字节,适用于位运算、密码学或协议解析等场景。

在单个字节上执行左移(整体左移一位时,关键在于处理跨字节进位:前一个字节的最高位(bit 7)应作为后一个字节的最低位(bit 0)的输入。这本质上是将整个字节数组视为一个大端排列的二进制大整数,并对其执行一次逻辑左移。

以下是一个健壮、通用的 shiftBytesLeft 函数实现:

func shiftBytesLeft(a []byte) []byte {     if len(a) == 0 {         return a     }     dst := make([]byte, len(a))     // 处理除最后一个字节外的所有字节:左移本字节,并从下一个字节借入最高位(作为本字节的 LSB)     for i := 0; i < len(a)-1; i++ {         dst[i] = a[i]<<1 | (a[i+1] >> 7)     }     // 最后一个字节仅左移,低位补 0(无后续字节提供进位)     dst[len(a)-1] = a[len(a)-1] << 1     return dst }

工作原理说明

  • a[i]
  • a[i+1] >> 7:取下一个字节的最高位(bit7),右移到最低位位置(即 0x01 或 0x00);
  • | 操作将该进位“填入”当前字节左移后空出的最低位(LSB);
  • 最后一个字节无后续字节可借位,因此只左移,LSB 补 0。

? 使用示例

func main() {     // 示例:2 字节数组 0xD3 0x4A → 二进制:11010011 01001010     src := []byte{0xD3, 0x4A}     fmt.Printf("原始: %08b %08bn", src[0], src[1]) // 11010011 01001010      shifted := shiftBytesLeft(src)     fmt.Printf("左移1位: %08b %08bn", shifted[0], shifted[1]) // 10100110 10010100 }

输出验证:

  • 0xD3(11010011)左移 → 1010011?,其 bit7(1)进位至下一字节 LSB;
  • 0x4A(01001010)左移 → 10010100,再与进位 1 组合 → 10010100(注意:此处进位实际加在 前一字节 的 LSB,即 0xD3>7 = 0?等等——需重新校验逻辑)

⚠️ 重要澄清与修正
上述函数中 dst[i] = a[i]>7) 的设计意图是——将 a[i+1] 的最高位“补到 a[i] 左移后的最低位”,这对应的是整个数组向左平移,高位溢出由右侧字节“供给”,即:

移动后,原 a[0] 的 bit7 成为 dst[0] 的 bit6,而 dst[0] 的 bit0 来自 a[1] 的 bit7 —— 这实际是循环左移风格?不,不是循环。

实际上,标准逻辑左移(非循环) 对多字节数组的定义是:

  • 整体视为一个大整数(大端),左移 1 位 ⇒ 所有比特向更高位移动,最低位补 0,最高位(即 a[0] 的 bit7)被丢弃。
    但用户原始单字节函数 SL 的行为是:若原字节最高位为 1,则左移后 XOR 0x01 —— 这并非标准移位,而是某种自定义混淆操作(如 LFSR 抽头反馈)。

然而,根据问题中明确诉求 “shift Array of bytes, like type Byte [2]byte”,并结合答案提供的函数,其目标是实现标准跨字节左移(带进位链),即:

Input:  [A7 A6 A5 A4 A3 A2 A1 A0] [B7 B6 B5 B4 B3 B2 B1 B0] Output: [A6 A5 A4 A3 A2 A1 A0 B7] [B6 B5 B4 B3 B2 B1 B0 0]

✅ 这正是 shiftBytesLeft 函数所实现的:

  • dst[0] = (A>7) → A6..A0 + B7
  • dst[1] = B

因此该函数正确且高效。

? 注意事项

  • 输入切片为空时需提前返回,避免 panic;
  • 该函数不修改原切片,返回全新分配的 []byte;
  • 若需原地操作,可传入 dst []byte 作为参数并复用底层数组;
  • 右移或循环移位需另行实现,逻辑不同;
  • 在密码学等敏感场景中,注意常数时间要求(当前实现非恒定时间,因分支隐含数据依赖)。

总结:使用 shiftBytesLeft 即可安全、清晰地完成字节数组的逻辑左移一位操作,它准确建模了多字节二进制数的位级平移行为,是处理网络协议、硬件寄存器或加密算法中常见需求的可靠基础工具

text=ZqhQzanResources