dtdsbakn210537 2019-04-13 10:27
浏览 104

如何在Go中正确使用系统调用(Go不安全的不同结果。Sizeof与C sizeof)

Go's unsafe.Sizeof is returning a different result than C's sizeof.

main.go:

package main

import (
    "unsafe"
)

type gpioeventdata struct {
    Timestamp uint64
    ID        uint32
}

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

Prints 12 when compiled with env GOOS=linux GOARCH=arm GOARM=6 go build on macOS and run on Raspberry Pi Zero.

gpio.c:

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

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

Prints 16 when compiled and run on Raspberry (with gcc).

struct definition in gpio.h:

struct gpioevent_data {
    __u64 timestamp;
    __u32 id;
};

Edit

I already thought that this is due to alignment, but a lot of people are passing Go structs to syscall.Syscall (e.g. https://github.com/stapelberg/hmgo/blob/master/internal/gpio/reset.go#L49). So that's basically wrong and you should never do that?

If that's wrong, what would be the correct approach calling syscalls with go so that works correctly with different architectures. For example GPIO ioctl calls:

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

2条回答 默认 最新

  • dongwen5019 2019-04-13 10:31
    关注

    The go compiler and the C compiler are handling alignment differently.

    In C the structure has been aligned to 16 bytes (adding a 4 bytes slack space after id or before it). The go compiler instead packed the fields without adding any slack space.

    Your mistake is thinking that two "structures" in different languages with different compilers should have the same memory layout.

    Note that there is no way to "compute" what will be the padding in a C or C++ structure because padding is a choice of the implementer. It's well possible that two different standard-conforming C compilers for the same architecture will generate different paddings (or even the same compiler with different compiling options).

    The only way to get the padding correct is to check the specific case, either manually or by writing a script that calls the compiler passing the same compiling options and checks the result (e.g. by output the results of offsetof on all the members) and then generates the needed go source code after parsing that output.

    评论

报告相同问题?

悬赏问题

  • ¥15 一道python难题2
  • ¥15 一道python难题
  • ¥15 用matlab 设计一个不动点迭代法求解非线性方程组的代码
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备