Quick summary, I'm trying to understand the Go structures that cgo
gives me, how they map back onto the C structures and why a Go struct
that doesn't quite match the cgo output seems to work anyway.
I've called out two explicit questions down below.
---
The Linux kernel provides a character device interface to I2C devices,
and the [i2c-tools] package provides a C library with "convenient"
access functions.
I'm working on a Go library for the kernel interface on a Raspberry
Pi, because I need it for a project *and* as an etude [so please,
don't do too much of my "homework" for me...;)]
While digging around for prior art, I found a [partial implementation
by tetsu-koba][tetsu-koba]. Starting from that, I have working bits
to talk to devices via the I2C versions of the commands.
My next step was to implement the [i2c-tools] SMBus functions. That
requires Go versions of the two C structures that they use. A bit of
research into creating the mapping led to using `cgo -godefs`. Along
the way, I stumbled on a [partial implementation of the SMBus
bits][brandonagr-smbus] by
brand...@gmail.com.
I ended up with this cgo input file:
```go
package main
/*
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
*/
import "C"
type I2CMsg C.struct_i2c_msg
const Sizeof_I2CMsg = C.sizeof_struct_i2c_msg
type I2CSMBusIoctlData C.struct_i2c_smbus_ioctl_data
const Sizeof_I2CSMBusIoctlData = C.sizeof_struct_i2c_smbus_ioctl_data
type Blort C.struct_blort
type I2CSMBusData C.union_i2c_smbus_data
const Sizeof_I2CSMBusData = C.sizeof_union_i2c_smbus_data
```
It generates this output:
```go
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs foo.go
package main
type I2CMsg struct {
Addr uint16
Flags uint16
Len uint16
Buf *uint8
}
const Sizeof_I2CMsg = 0xc
type I2CSMBusIoctlData struct {
Write uint8
Command uint8
Size uint32
Data *[34]byte
}
const Sizeof_I2CSMBusIoctlData = 0xc
type Blort struct{}
type I2CSMBusData [34]byte
const Sizeof_I2CSMBusData = 0x22
```
@brandonagr ended up with something that's different for his version
of the i2c_smbus_ioctl_data struct:
```go
type i2c_smbus_ioctl_data struct {
read_write uint8
command uint8
size int
data *uint8
}
```
but I can see how it's the same "shape".
## Question #1
On the *other hand, @tetsu-koba's version of the i2c_msg struct:
```go
type i2c_msg struct {
addr uint16
flags uint16
len uint16
__padding uint16
buf uintptr
}
```
seems to be fundamentally different from the `cgo -godefs` version:
```go
type I2CMsg struct {
Addr uint16
Flags uint16
Len uint16
Buf *uint8
}
```
Before I figured out how to use `cgo -godefs`, I rationalized
@tetsu-koba's struct with the explanation that the `buf` pointer was
being padded out to a 32-bit boundary and was comforted by the fact
that it seems to work (I can use it to talk to e.g. an MCP9808
temperature sensor).
But, the `cgo -godefs` output seems to be a different shape, I don't
see how the Buf field ends up in the right place. I haven't tried
*using* it yet, I'd like to understand the why before I comfort myself
with a "seems to work, onward...". Left to my own devices I thought
about trying to get at the assembly language output for the various
structs and seeing what was going on, but that seemed to be One Yak
Too Far.
Can anyone explain [or a big big clue] what's going on? Is one right
and the other wrong? Are both somehow correct?
## Question #2
While I'm on this topic, I notice that `cgo -godefs` converted the
struct/field names to Go camel case versions (and stripped the "read_"
prefix from one). But, both @tetsu-koba and @brandonagr stuck with
the C struct names. I've noticed that various go libaries that refer
to kernel data structures (e.g. constants/#defines) don't rename them
in Go style.
What is the accepted practice in this situation?
Thanks!
g.
[brandonagr-smbus]:
https://groups.google.com/d/msg/golang-nuts/zHyqv36oFVI/Jzx1ztCZbHwJ
[i2c-tools]:
https://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git/
[tetsu-koba]:
https://gist.github.com/tetsu-koba/33b339d26ac9c730fb09773acf39eac5