Go Basics: Encode Fixed-Width Records with Explicit Byte Order
Binary formats need agreed field widths and byte order. Build a small header with a two-byte version and a four-byte payload length, then decode it without depending on Go struct padding.
Prepare a scratch directory
Tested on Linux amd64 with Go 1.26.10. Install Go and make go available on PATH. You also need Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. The example uses only the standard library and needs no module or external dependency.
Keep the same terminal open. Stop if setup fails, before saving the source:
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1Run the example
Save this as binary-byte-order-demo.go:
package main
import (
"encoding/binary"
"fmt"
)
func decode(data []byte) (uint16, uint32, error) {
if len(data) != 6 {
return 0, 0, fmt.Errorf("header must contain six bytes")
}
return binary.BigEndian.Uint16(data[:2]), binary.BigEndian.Uint32(data[2:]), nil
}
func main() {
data := make([]byte, 6)
binary.BigEndian.PutUint16(data[:2], 3)
binary.BigEndian.PutUint32(data[2:], 1024)
fmt.Printf("Bytes: % x\n", data)
version, length, err := decode(data)
if err != nil {
panic(err)
}
fmt.Printf("Version=%d length=%d\n", version, length)
_, _, err = decode(data[:5])
fmt.Println("Short header rejected:", err != nil)
}Run it:
go run binary-byte-order-demo.goObserved output:
Bytes: 00 03 00 00 04 00
Version=3 length=1024
Short header rejected: trueRead the result
Big-endian encoding writes the most significant byte first. Fixed-width unsigned integers make the on-wire layout explicit. The length guard runs before slicing or decoding; otherwise a short input can cause a panic. The invalid input is an expected test case.
Apply it carefully
A decoded length is still untrusted data. Check it against application limits before allocating or reading a payload. This decoder intentionally requires exactly one header; a stream parser should read the required number of bytes, handle truncation, and leave the payload for the next step.
The official Go reference documents the behavior used here.
Clean up
Remove the saved source, return to the starting directory, and remove the empty practice directory. go run does not leave an executable here; Go manages its build cache separately.
rm -- binary-byte-order-demo.go
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dirIf the directory is not empty, inspect its remaining contents before removing anything else.
Acknowledgements
This post was created with assistance from AI.