我正在编写一个小程序来使用 Go 检查字节序:
var i int = 0x0100
ptr := unsafe.Pointer(&i)
if 0x01 == *(*byte)(ptr) {
fmt.Println("Big Endian")
} else if 0x00 == *(*byte)(ptr) {
fmt.Println("Little Endian")
} else {
// ...
}
I
import "unsafe"
软件包将 *int
转换为 *byte
。
但正如https://golang.org/pkg/unsafe/中提到的:
包不安全包含绕过 Go 程序类型安全的操作。
导入不安全的包可能是不可移植的,并且不受 Go 1 兼容性指南的保护。
是否有更好的方法来确定字节顺序,或者我是否必须使用不安全的包?
虽然仍然依赖于
unsafe
包,但 Google 的 TensorFlow API for Go 有一个很好的解决方案(参见 tensor.go)来测试机器的字节序:
var nativeEndian binary.ByteOrder
func init() {
buf := [2]byte{}
*(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xABCD)
switch buf {
case [2]byte{0xCD, 0xAB}:
nativeEndian = binary.LittleEndian
case [2]byte{0xAB, 0xCD}:
nativeEndian = binary.BigEndian
default:
panic("Could not determine native endianness.")
}
}
您想要做的是特定于体系结构的事情,据我所知,Go 并没有做太多事情来帮助您确定主机的字节顺序。使用不安全指针的解决方案可能是您能做的最好的解决方案。
如果您知道要使用的字节顺序并相应地进行编码/解码,则可以使用
encoding/binary
包:https://godoc.org/encoding/binary#ByteOrder
如果您确实需要依赖主机字节顺序,您可能会陷入一种设计反模式,您应该尽可能避免这种模式:https://commandcenter.blogspot.com/2012/04/byte- order-fallacy.html
这里还有关于 golang-nuts 的关于这个话题的热烈讨论,辩论双方都表达了自己的观点:https://groups.google.com/forum/#!topic/golang-nuts/3GEzwKfRRQw
该电子邮件线程有 Russ Cox 的建议,即使用构建约束静态定义所需的字节顺序(或主机字节顺序):
几个月来我们的代码已经:
var hbo = binary.LittleEndian // hack - 我们想要主机字节顺序!
所以我们可以使用encoding.Binary来读取东西。
将其放入名为 byteorder_amd64.go 的文件中并 它不再是一个黑客。它不需要在标准中 图书馆。
希望有帮助...
也许这个代码可以帮助你。
这可以检查机器字节顺序:
//true = big endian, false = little endian
func getEndian() (ret bool) {
var i int = 0x1
bs := (*[INT_SIZE]byte)(unsafe.Pointer(&i))
if bs[0] == 0 {
return true
} else {
return false
}
}
var bigEndian = (*(*[2]uint8)(unsafe.Pointer(&[]uint16{1}[0])))[0] == 0
顺便说一句,我怀疑你原来的逻辑是非法的:
var i int = 0x0100
ptr := unsafe.Pointer(&i)
if 0x01 == *(*byte)(ptr) {
如果将
*T
转换为 unsafe.Pointer
,然后转换为另一种类型 *U
,则 U
和 T
必须具有等效的内存布局。 https://golang.org/pkg/unsafe/#Pointer
从 Go 1.21.0 开始,stdlib 包
encoding/binary
最终导出 binary.NativeEndian
。如果您不关心其特定的字节顺序,而只想 binary.NativeEndian
进行正确的编码或解码,这应该足够了。
如果您的模块遵循“支持最后两个 Go(次要)版本”规则,那么您现在可以直接使用
binary.Native
,而无需滚动自己的支持功能或包。
最后,如果您想知道 concrete 原生字节顺序,不幸的是
binary.Native
没有明确告诉您,因为 String()
总是返回 "NativeEndian"
。因此,在这个特定的用例中,您必须进行如下测试:
little := binary.NativeEndian.Uint16([]byte{0x12, 0x34}) == uint16(0x3412)