今天在golang指针类型转换上遇到的一些问题,这里记录一下,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"unsafe"
)

func main() {
var f float32
f = 3.0
var a int
a = *(*int)((unsafe.Pointer(&f)))
fmt.Println((*int)((unsafe.Pointer(&f))))
fmt.Println(&f)
fmt.Println(a)
fmt.Println(int(f))
}

这个代码的意思是将浮点指针类型转换为整数的指针类型,运行之后输出的结果是:

1
2
3
4
0xc0000120a0
0xc0000120a0
1077936128
3

这里就没想明白了,明明地址都相同,但是为什么输出的结果确截然不同呢。

经过一番思考之后,猜测应该是直接把内存中存储的浮点数转换为了整型,浮点数在内存是遵循IEEE 754标准的

任何浮点数都可以这么表示:float = (-1) ^ S * M * 2 ^ E

Sign (1bit):表示浮点数是正数还是负数。0表示正数,1表示负数
Exponent (8bits):指数部分。以2为底的科学计数法。
Mantissa (23bits):基数部分。浮点数具体数值的实际表示。

我们上面f是单精度(float32),占用4个字节,共32位大小,表示为:1位符号,8位指数,23位小数。

我们现在来把上面的3.0转化为内存中存储形式
3.0转化为二进制为11.0,然后用以2为底的科学计数法表示:1.10*2^1。然后是整数符号位S为0;指数部分为1,然后再加上127变为128,因为计数中指数是可以为负的,所以规定在存入E时,在它原本的值上加上中间数(127),在使用时减去中间数(127);基数部分为10,然后在后面再填充21个0补全23位。最终为:S+E+M,即:0 10000000 10000000000000000000000,转化为10进制为:1077936128,刚好对应了上面的结果。