-
Notifications
You must be signed in to change notification settings - Fork 7
Description
When trying to generate bindings for the bmx280
device driver, I noticed that the size of the struct bmx280_params_t
differs from C to Rust. I used the module USEMODULE += bmp280_i2c
and added these lines to rust-riot-sys/riot-headers.h
to generate the bindings:
#include "bmx280.h"
#include "bmx280_params.h"
The struct contains an i2c_dev
of type i2c_t
which seems to be the reason for the difference. I used the following programs to print the sizes. In C:
#include <stdio.h>
#include <bmx280.h>
int main(void) {
printf("sizeof bmx280_params_t = %d\n", sizeof(bmx280_params_t));
printf("sizeof i2c_t = %d\n", sizeof(i2c_t));
}
sizeof bmx280_params_t = 32
sizeof i2c_t = 4
In Rust:
use riot_wrappers::{println, riot_main};
use riot_sys::{bmx280_params_t, i2c_t};
use core::mem::size_of;
riot_main!(main);
fn main() {
println!("sizeof bmx280_params_t = {}", size_of::<bmx280_params_t>());
println!("sizeof i2c_t = {}", size_of::<i2c_t>());
}
sizeof bmx280_params_t = 28
sizeof i2c_t = 1
In the file RIOT/drivers/include/periph/i2c.h
the type is defined as follows:
#ifndef HAVE_I2C_T
typedef uint_fast8_t i2c_t;
#endif
For native, xtensa, risc-v and arm, it seems like all the fast integer types are defined through internal compiler defines like typedef __INT_FAST8_TYPE__ int_fast8_t;
These types differ since RIOT is compiled by gcc and the Rust bindings are created with llvm. I did some tests and got the following types using different architectures. The cells show the actual type when using gcc / clang:
Bit | Native (x86-64) | Xtensa | RISC-V | ARM |
---|---|---|---|---|
8 | char / char | int / char | int / char | int / char |
16 | long int / short | int / short | int / short | int / short |
32 | long int / int | int / int | int / int | int / int |
64 | long int / long int | long long int / long long int |
long long int / long long int |
long long int / long long int |
One workaround is to redefine these macros when generating the bindings so that they match the types used by gcc. For the uint_fast8_t
this can be done by adding the following lines to riot-bindgen.h
and riot-c2rust.h
:
#undef __UINT_FAST8_TYPE__
#define __UINT_FAST8_TYPE__ unsigned int
Alternatively, this also works:
#define HAVE_I2C_T
typedef unsigned int i2c_t
However there should be a better way that actually guarantees that the same type is used when compiling RIOT and creating the bindings.