英文:
Why isn't binary.Read() reading integers correctly?
问题
我正在尝试在Go中读取一个二进制文件。
基本上,我有一个像这样的结构体:
type foo struct {
A int16
B int32
C [32]byte
// 其他字段...
}
我正在像这样从文件中读取到结构体中:
fi, err := os.Open(fname)
// 错误检查,延迟关闭等
var bar foo
binary.Read(fi, binary.LittleEndian, &bar)
现在,这个应该可以工作,但我得到了一些奇怪的结果。例如,当我读取到结构体中时,我应该得到这样的结果:
A: 7
B: 8105
C: // 一些字符串
但我得到的结果是:
A: 7
B: 531169280
C: // 一些正确的字符串
这是因为当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];
// 你懂的...
} foo;
int sz = sizeof(struct cool_struct);
const char* file_name = "/path/to/my/file";
fd = open(file_name, O_RDONLY);
// 更多代码
read(fd, &foo, sz);
// 打印值
}
我得到了正确的结果。为什么我的C代码能够得到正确的结果,而我的Go代码却不能呢?
英文:
I'm trying to read a binary file in Go.
Essentially I have a struct like this:
<!-- language: lang-go -->
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:
<!-- language: lang-go -->
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:
<!-- language: 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?
答案1
得分: 6
假设字符串的前两个字符不是'\000',你遇到的问题是对齐问题,你的C编译器在int16后面添加了额外的两个字节,而Go语言没有这样做。
最简单的解决方法可能是在'A'后面添加一个虚拟(填充)int16:
type foo struct {
A int16
A_pad int16
B int32
C [32]byte
}
或者可能有一种方法告诉Go语言int32需要"4字节对齐",如果你知道这种方法,请编辑这个答案或发表评论。
英文:
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
答案2
得分: 1
给定的代码部分如下所示:
0000000: 0700 0000 a91f 0000 7074 732f 3300 0000 ........pts/3...
根据结构体,字段的含义如下:
0700h 是一个短整型字段,小端格式 = 7
0000a91fh 是一个整型字段,小端格式 = 一个很大的数字
...
你的结构体需要一个第二个短整型字段来接收 0000h
然后
0700h = 7
0000h = 新字段中的 0
a91f0000 = 8105
....
这表明(除其他外),结构体在短整型字段和整型字段之间缺少了预期的两个字节的填充。
C 代码中是否有 #pragma pack 指令?
英文:
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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论