Reputation: 511
I'm trying to read a binary file in Go.
Essentially I have a struct like this:
type foo struct {
A int16
B int32
C [32]byte
// and so on...
}
and I'm reading from the file into the struct like this:
fi, err := os.Open(fname)
// error checking, defer close, etc.
var bar foo
binary.Read(fi, binary.LittleEndian, &bar)
Now, that should work, but I'm getting some weird results. For instance, when I read into the struct I should get this:
A: 7
B: 8105
C: // some string
but what I get is this:
A: 7
B: 531169280
C: // some correct string
The reason for this is because when binary.Read()
is reading the file, after it reads the []byte{7, 0}
as int16(7)
(the correct value for A
), it comes across the slice []byte{0, 0, 169, 31}
and tries to convert it into an int32
. However, binary.Read()
's conversion does this:
uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
where b
is the byte slice.
But what really confuses me is doing the exact same thing in C works perfectly fine.
If I write this in C:
int main()
{
int fd;
struct cool_struct {
short int A;
int32_t B;
char C[32];
// you get the picture...
} foo;
int sz = sizeof(struct cool_struct);
const char* file_name = "/path/to/my/file"
fd = open(file_name, O_RDONLY);
// more code
read(fd, &foo, sz);
// print values
}
I get the correct results. Why is my C code getting this correct while my Go code isn't?
Upvotes: 1
Views: 116
Reputation: 16540
given:
0000000: 0700 0000 a91f 0000 7074 732f 3300 0000 ........pts/3...
the fields, per the struct, are:
0700h that will be the short int field, little endian format = 7
0000a91fh that will be the int field, little endian format = the big number
...
your struct needs a second short field to absorb the 0000h
then
0700h = 7
0000h = 0 in new field
a91f0000 = 8105
....
which indicates (amongst other things) that the struct is missing
the expected 2 byte padding between the short and the int fields
does the C code have #pragma pack?
Upvotes: 1
Reputation: 12412
Assuming the first two characters of the string aren't '\000'
what you've got there is an alignment problem, your C compiler is putting an extra two bytes of padding after the int16, Go isn't
easiest fix is probably just to add a dummy (padding) int16 after 'A'
type foo struct
{
A int16
A_pad int16
B int32
C [32]byte
}
or the may be a way to tell go that the int32 needs to be "4-byte aligned"
if you know of one please edit this answer or post a comment
Upvotes: 6