Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any better way to check endianness in Go

Tags:

go

endianness

I am writing a small program to check the endianness using 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" package to convert *int to *byte. But as mentioned in https://golang.org/pkg/unsafe/:

Package unsafe contains operations that step around the type safety of Go programs.

Packages that import unsafe may be non-portable and are not protected by the Go 1 compatibility guidelines.

Is there a better way to determine endianness, or do I have to use unsafe package?

like image 577
Cubey Mew Avatar asked Jul 13 '18 20:07

Cubey Mew


People also ask

Is there a quick way to determine endianness of your machine?

Is there a quick way to determine endianness of your machine? There are n no. of ways for determining endianness of your machine.

How do you test for endianness?

If it is little-endian, it would be stored as “01 00 00 00”. The program checks the first byte by dereferencing the cptr pointer. If it equals to 0, it means the processor is big-endian(“00 00 00 01”), If it equals to 1, it means the processor is little-endian (“01 00 00 00”).

How do you know if you are big or little endian?

Big-endian is an order in which the "big end" (most significant value in the sequence) is stored first, at the lowest storage address. Little-endian is an order in which the "little end" (least significant value in the sequence) is stored first.

What is the most common endianness?

By far the most common ordering of multiple bytes in one number is the little-endian, which is used on all Intel processors.


2 Answers

Although still relying on the unsafe package, Google's TensorFlow API for Go has a nice solution (see tensor.go) for testing the endianness of your machine:

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.")
    }
}
like image 69
nmurthy Avatar answered Oct 14 '22 09:10

nmurthy


What you want to do is architecture-specific, and Go doesn't do a whole lot to help you determine your host's byte order as far as I can tell. Your solution using unsafe pointers is probably the best you can do.

If you know the byte order you want to speak in and encode/decode accordingly, you can use the encoding/binary package for that: https://godoc.org/encoding/binary#ByteOrder

If you truly need to rely on host byte order, you might be banging your head on a design anti-pattern that you should try to avoid if possible: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

Also here's a spirited discussion on golang-nuts about this very topic, with opinions expressed on both sides of the debate: https://groups.google.com/forum/#!topic/golang-nuts/3GEzwKfRRQw

That email thread has a suggestion by Russ Cox to just statically define the desired byte order (or the host byte order) using build constraints:

For months now our code has had:

var hbo = binary.LittleEndian // hack - we want host byte order!

so we can use encoding.Binary to read things.

Put that in a file named byteorder_amd64.go and it stops being a hack. It need not be in the standard library.

Hope that helps...

like image 25
Eddy R. Avatar answered Oct 14 '22 08:10

Eddy R.