You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Golang处理负数时会进行位翻转操作?

为什么负数的二进制内存存储不是仅翻转符号位?

我想查看数字在内存中的原始存储形式,用Go的unsafe指针做验证,我的机器是小端序(最低有效字节在最低地址,打印时排在首位)。

编写的Go代码如下:

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    var x1 int32 = 1240
    ptr1 := unsafe.Pointer(&x1)
    value1 := (*[4]byte)(ptr1)
    fmt.Printf("x1 = 1240 in binary representation: %08b\n", value1)

    var x2 int32 = -1240
    ptr2 := unsafe.Pointer(&x2)
    value2 := (*[4]byte)(ptr2)
    fmt.Printf("x2 = -1240 in binary representation: %08b\n", value2)
}

执行后输出:

x1 = 1240 in binary representation: &[11011000 00000100 00000000 00000000]
x2 = -1240 in binary representation: &[00101000 11111011 11111111 11111111]

我预期-1240的输出是:

x2 = -1240 in binary representation: &[11011000 00000100 00000000 10000000]

也就是仅符号位从0变1,但实际输出是所有位翻转的情况,这是为什么?


这是因为计算机系统中整数的存储和运算使用的是补码,而非你预期的原码。

原码是最直观的表示方式:正数符号位为0,负数符号位为1,其余位是数值的二进制。但原码做加减法时需要单独处理符号位,效率低,所以现代计算机都用补码来统一正负数的运算逻辑。

补码的规则:

  • 正数的补码与原码完全相同
  • 负数的补码 = 对应正数的原码按位取反(得到反码)后加1

结合你的例子计算:

  1. 先看1240的int32原码(小端序存储,字节顺序是低到高):
    1240的二进制是00000000 00000000 00000100 11011000,小端序存储后字节顺序为11011000 00000100 00000000 00000000,和你代码输出的x1一致。

  2. 计算-1240的补码:

    • 先对1240的原码按位取反(反码):11111111 11111111 11111011 00100111
    • 然后加1得到补码:11111111 11111111 11111011 00101000
    • 按小端序存储,字节顺序反转成00101000 11111011 11111111 11111111,这和你代码输出的x2完全一致。

你预期的是原码的存储方式,但实际上Go(和几乎所有现代编程语言)都遵循补码的存储规则,所以会出现这样的结果。

内容的提问来源于stack exchange,提问作者LeaBit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 05:21:05