gpt4 book ai didi

go - 如何在 go 中正确使用系统调用(Go unsafe.Sizeof 与 C sizeof 的不同结果)

转载 作者:IT王子 更新时间:2023-10-29 01:40:31 35 4
gpt4 key购买 nike

Go 的 unsafe.Sizeof 返回的结果与 C 的 sizeof 不同。

main.go:

package main

import (
"unsafe"
)

type gpioeventdata struct {
Timestamp uint64
ID uint32
}

func main() {
eventdata := gpioeventdata{}
println("Size", unsafe.Sizeof(eventdata))
}

在 macOS 上使用 env GOOS=linux GOARCH=arm GOARM=6 go build 编译并在 Raspberry Pi Zero 上运行时打印 12

gpio.c:

#include <stdio.h>
#include <linux/gpio.h>

int main() {
printf("sizeof gpioevent_data %zu\n", sizeof(struct gpioevent_data));
}

在 Raspberry 上编译和运行时打印 16(使用 gcc)。

gpio.h 中的结构体定义:

struct gpioevent_data {
__u64 timestamp;
__u32 id;
};

编辑

我已经认为这是由于对齐,但很多人正在将 Go 结构传递给 syscall.Syscall(例如 https://github.com/stapelberg/hmgo/blob/master/internal/gpio/reset.go#L49)。所以这基本上是错误的,你永远不应该这样做?

如果那是错误的,那么使用 go 调用系统调用的正确方法是什么,以便在不同的体系结构中正常工作。例如 GPIO ioctl 调用:

ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req);
...
struct gpioevent_data event;
ret = read(req.fd, &event, sizeof(event));

最佳答案

go 编译器和 C 编译器处理对齐的方式不同。

在 C 中,结构已对齐到 16 字节(在 id 之后或之前添加 4 字节的松弛空间)。 go 编译器在不添加任何松弛空间的情况下打包字段。

您的错误是认为使用不同编译器的不同语言的两个“结构”应该具有相同的内存布局。

请注意,无法“计算”C 或 C++ 结构中的填充内容,因为填充是实现者的选择。很可能同一架构的两个不同的符合标准的 C 编译器会生成不同的填充(甚至是具有不同编译选项的同一编译器)。

获得正确填充的唯一方法是检查具体情况,手动或编写脚本调用编译器传递相同的编译选项并检查结果(例如,通过输出 offsetof< 的结果 在所有成员上),然后在解析该输出后生成所需的 go 源代码。

关于go - 如何在 go 中正确使用系统调用(Go unsafe.Sizeof 与 C sizeof 的不同结果),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55664457/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com