Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alignment in golang

I am implementing a network packet in golang. It was already implemented in C++. The purpose is to make the golang implemented client communicate with C++ implemented server.

They will communicate by packet. The packet struct is:

type Packet struct {
    length   uint32
    nameLen  uint8
    data     []byte
} // in golang

struct Packet {
    uint32_t length;
    uint8_t  nameLen;
    byte     data[];
} // in C++

Their underlined structure is byte array. When receiving a message in byte array format. We need to translate it into Packet.

auto p = reinterpret_cast<Packet*>(buffer); // in c++
(buffer's alignment is manually set as 64)

p := (Packet)(unsafe.Pointer(&buffer)) // in golang

To make them communicate, their struct alignment should keep the same.

Here comes the question: After printing out their alignment, I get this:

type Packet struct {
    length  uint32 // alignment 8
    nameLen uint8  // alignment 8
    data    []byte // alignment 8
}
struct Packet {
    uint32_t length;  // alignment 4
    uint8    nameLen; // alignment 4
    data     []byte;  // alignment 1
}

They will decode the message differently due to the alignment is different.

I can not change the C++ code.

Q1: Is there any way to set struct fields alignment in golang?

Q2: Is there a better way to implement golang Packet to avoid alignment mismatch when casting buffer into packet?

like image 416
Cubey Mew Avatar asked Oct 16 '22 09:10

Cubey Mew


1 Answers

According to Adrian and Volker's comment,

Q1: No

Q2: Do some programming to unpack fields individually.

In encoding/binary package, we have

func PutUVarint

It encodes a uint64 into buf and returns the number of bytes written. Somehow this package dont have public function to encode uint32. So I did something similar:

func PutUint32(b []byte, v uint32) {
    _ = b[3] // early check
    b[0] = byte(v)
    b[1] = byte(v >> 8)
    b[2] = byte(v >> 16)
    b[3] = byte(v >> 24)
} // assume it's littleEndian

// to store packet length into buffer.
PutUint32(buffer, pkt.length)
like image 142
Cubey Mew Avatar answered Oct 20 '22 09:10

Cubey Mew