Go 两个';s补码与fmt.Printf

Go 两个';s补码与fmt.Printf,go,Go,所以计算机使用2的补码在内部表示有符号整数。即,-5表示为^5+1=“1111 1011” 但是,尝试打印二进制表示,例如以下代码: var i int8 = -5 fmt.Printf("%b", i) 输出-101。不完全是我所期望的。格式是不同的还是根本不使用二的补码 有趣的是,转换为无符号整数会产生“正确”的位模式: var u uint8 = uint(i) fmt.Printf("%b", u) 输出为11111 011-正好是-5的2s补码 因此,在我看来,该值在内部是真正使用

所以计算机使用2的补码在内部表示有符号整数。即,-5表示为^5+1=“1111 1011”

但是,尝试打印二进制表示,例如以下代码:

var i int8 = -5
fmt.Printf("%b", i)
输出
-101
。不完全是我所期望的。格式是不同的还是根本不使用二的补码

有趣的是,转换为无符号整数会产生“正确”的位模式:

var u uint8 = uint(i)
fmt.Printf("%b", u)
输出为
11111 011
-正好是
-5
的2s补码

因此,在我看来,该值在内部是真正使用二的补码的值,但格式是打印无符号的
5
并在
-
前面加上前缀


有人能澄清一下吗?

我相信答案在于
fmt
模块如何格式化二进制数,而不是内部格式

如果您看一看,函数执行的第一个操作之一是将负有符号整数转换为正整数:

   165      negative := signedness == signed && a < 0
   166      if negative {
   167          a = -a
   168      }
165负:=signedness==signed&&a<0
166如果是负数{
167A=-a
168      }
然后在输出的字符串前面添加
-
逻辑

IOW
-101
实际上是以二进制形式附加到
5
之后的
-


注意:
fmt.integer
是从
pp.fmtInt64
中调用的,它本身是从同一函数中的
pp.printArg
中调用的。

必须使用不安全指针以二进制格式正确表示负数

package main

import (
    "fmt"
    "strconv"
    "unsafe"
)

func bInt8(n int8) string {
    return strconv.FormatUint(uint64(*(*uint8)(unsafe.Pointer(&n))), 2)
}

func main() {
    fmt.Println(bInt8(-5))
}
输出

11111011

我不知道为什么有人会认为这很“奇怪”。不管你用什么基数,负数仍然是负数。如果你在8、12或16垒要求,我也会期待同样的结果。我没说奇怪。我只是试着理解2s补码,结果并不是我所期望的。我不认为你真的可以通过玩用高级语言编写的数字格式函数来理解2的补码。你有什么建议?