为什么binary.Read()没有正确读取整数?

时间:2015-01-02 10:20:47

标签: c struct go

我正在尝试在Go中读取二进制文件。

基本上我有这样的结构:

type foo struct {
    A int16
    B int32
    C [32]byte
    // and so on...
}

我正在从文件中读到这样的结构:

fi, err := os.Open(fname)
// error checking, defer close, etc.
var bar foo
binary.Read(fi, binary.LittleEndian, &bar)

现在,应该工作,但我得到一些奇怪的结果。例如,当我读到结构时,我应该得到这个:

A: 7
B: 8105
C: // some string

但我得到的是:

A: 7
B: 531169280
C: // some correct string

原因是因为当binary.Read()正在读取文件时,在[]byte{7, 0}读取int16(7)A的正确值)之后,它会遇到切片[]byte{0, 0, 169, 31}并尝试将其转换为int32。但是,binary.Read()的转换是这样做的:

uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24其中b是字节切片。

但是让我感到困惑的是在C中做同样的事情完全没问题。

如果我用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
}

我得到了正确的结果。为什么我的C代码在我的Go代码不正确时才能正确显示?

2 个答案:

答案 0 :(得分:6)

假设字符串的前两个字符不是&#39; \ 000&#39;

你所遇到的是一个对齐问题,你的C编译器在int16之后增加了两个字节的填充,Go isn&#t; t

最简单的修复可能只是在&#39; A&#39;

之后添加一个虚拟(填充)int16
type foo struct 
{
    A int16
    A_pad int16
    B int32
    C [32]byte
}

或者可能是一种告诉你int32需要&#34; 4字节对齐&#34;

的方法

如果你知道一个,请编辑这个答案或发表评论

答案 1 :(得分:1)

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?