mem::offset_of!() 宏

这个宏用于获取结构体成员的相对于结构体起始内存的偏移量, 类似于 libc 中的 offsetof() 函数.

下面是一个示例程序:

#![allow(non_camel_case_types)]

use std::mem;

// rustc 决定内存布局
pub struct linux_dirent_t {
    pub d_ino: u64,
    pub d_off: u64,
    pub d_reclen: u16,
    pub d_type: u8,
    pub d_name: *mut u8,
}

// 使用 C ABI 兼容的内存布局
#[repr(C)]
pub struct linux_dirent_c_t {
    pub d_ino: u64,
    pub d_off: u64,
    pub d_reclen: u16,
    pub d_type: u8,
    pub d_name: *const u8,
}

// 为结构体添加 packed attribute, 忽略结构体内成员的内存对齐.
#[repr(packed)]
pub struct linux_dirent_packed_t {
    pub d_ino: u64,
    pub d_off: u64,
    pub d_reclen: u16,
    pub d_type: u8,
    pub d_name: *const u8,
}

fn main() {
    assert_eq!(mem::offset_of!(linux_dirent_t, d_name), 16);
    assert_eq!(mem::offset_of!(linux_dirent_c_t, d_name), 24);
    assert_eq!(mem::offset_of!(linux_dirent_packed_t, d_name), 19);
}

对应的 C 代码如下:

#include <stdint.h>
#include <stddef.h>
#include <assert.h>

struct linux_dirent_s {
  uint64_t d_ino;
  uint64_t d_off;
  uint16_t d_reclen;
  uint8_t d_type;
  char* d_name;
};

struct linux_dirent_packed_s {
  uint64_t d_ino;
  uint64_t d_off;
  uint16_t d_reclen;
  uint8_t d_type;
  char* d_name;
} __attribute__((packed));

int main(void) {
  assert(offsetof(struct linux_dirent_s, d_name) == 24);
  assert(offsetof(struct linux_dirent_packed_s, d_name) == 19);

  return 0;
}