与C语言兼容的结构体
使用 #repr(C)]
标志, 可以让 Rust 中定义的结构体的内存布局与 C 编译器生成的保持一致.
除了使用相同的内存排布方式外, 其结构体中的元素, 也应该选用与C语言兼容的类型.
对于结构体内存排布, C/C++编译器里的规则概括如下:
- 结构体里的元素顺序, 与其声明顺序保持一致
- 毎个元素都要占用独立的内存地址
- 内存对齐规则(待补充)
#![allow(unused)] fn main() { use std::ffi::{c_int, c_ulong}; #[repr(C)] #[derive(Debug, Default, Clone, Copy)] #[allow(non_camel_case_types)] pub struct shm_info_t { pub used_ids: c_int, /// total allocated shm pub shm_tot: c_ulong, /// total resident shm pub shm_rss: c_ulong, /// total swapped shm pub shm_swp: c_ulong, swap_attempts: c_ulong, swap_successes: c_ulong, } }
与之对应的, 在C语言中的定义是:
struct shm_info {
int used_ids;
__kernel_ulong_t shm_tot; /* total allocated shm */
__kernel_ulong_t shm_rss; /* total resident shm */
__kernel_ulong_t shm_swp; /* total swapped shm */
__kernel_ulong_t swap_attempts;
__kernel_ulong_t swap_successes;
};
枚举类型
枚举类型与结构体的声明方式类似, 看一个linux/perf_event.h
中的例子:
#![allow(unused)] fn main() { /// attr.type #[repr(u8)] #[allow(non_camel_case_types)] pub enum perf_type_id_t { PERF_TYPE_HARDWARE = 0, PERF_TYPE_SOFTWARE = 1, PERF_TYPE_TRACEPOINT = 2, PERF_TYPE_HW_CACHE = 3, PERF_TYPE_RAW = 4, PERF_TYPE_BREAKPOINT = 5, /// non-ABI PERF_TYPE_MAX = 6, } }
默认情况下, C语言中的枚举类型使用 int
作为基础类型, 但也可以手动指定别的类型, 比如:
#include <stdint.h>
enum perf_type_id_t : uint16_t {
PERF_TYPE_HARDWARE = 0,
PERF_TYPE_SOFTWARE = 1,
PERF_TYPE_TRACEPOINT = 2,
PERF_TYPE_HW_CACHE = 3,
PERF_TYPE_RAW = 4,
PERF_TYPE_BREAKPOINT = 5,
// non-ABI
PERF_TYPE_MAX = 6,
};
此时, 在 Rust 中, 可以使用 #[repr(u16)]
标记来实现一致的定义:
#![allow(unused)] fn main() { #[repr(u16)] #[allow(non_camel_case_types)] pub enum perf_type_id_t { PERF_TYPE_HARDWARE = 0, PERF_TYPE_SOFTWARE = 1, PERF_TYPE_TRACEPOINT = 2, PERF_TYPE_HW_CACHE = 3, PERF_TYPE_RAW = 4, PERF_TYPE_BREAKPOINT = 5, // non-ABI PERF_TYPE_MAX = 6, } }
Union 类型
Rust 里定义 union 与在 C 语言中类似:
#![allow(unused)] fn main() { use std::ffi::c_void; #[repr(C)] #[derive(Clone, Copy)] #[allow(non_camel_case_types)] pub union sigval_t { pub sival_int: i32, pub sival_ptr: *mut c_void, } }
原始的 sigval_t
是这样定义的:
// From <siginfo.h>
typedef union sigval {
int sival_int;
void *sival_ptr;
} sigval_t;