【发布时间】:2015-01-02 10:20:47
【问题描述】:
我正在尝试在 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 代码却没有?
【问题讨论】:
-
我记得某些版本的 C 可以以中端形式编写 32 位整数。您可以发布文件开头的十六进制转储吗?
-
@Jasen 使用 xxd:
0000000: 0700 0000 a91f 0000 7074 732f 3300 0000 ........pts/3... -
改变一切,你的 int16 是 4 个字节长 :)
-
@Jasen 但是在 Go 中 int16 是 2 个字节长。例如:play.golang.org/p/u1_bBJSeSo
-
@eric_lagergren 它也在 C 中,实际发生的是 C 编译器在 int16_t 之后添加了一些填充,以便 int32_t 可以 4 字节对齐