Memory Align

C

#include <iostream>
#include <tuple>
struct Padding1 {
char ch1;
char ch2;
int i_field;
double d_field;
};
struct Padding2 {
int i_field;
char ch1;
char ch2;
double d_field;
};
struct Padding3 {
char ch1;
int i_field;
char ch2;
double d_field;
};
template<typename T>
std::tuple<char*, char*, char*, char*> parse_padding() {
T t;
char* ch1 = &t.ch1;
char* ch2 = &t.ch2;
char* i_field = (char *) &t.i_field;
char* d_field = (char *) &t.d_field;
return std::make_tuple(ch1, ch2, i_field, d_field);
}
int main() {
std::cout << sizeof(Padding1) << std::endl;
std::cout << sizeof(Padding2) << std::endl;
std::cout << sizeof(Padding3) << std::endl;
Padding1 padding1;
char* ch1 = &padding1.ch1;
char* ch2 = &padding1.ch2;
char* i_field = (char *) &padding1.i_field;
char* d_field = (char *) &padding1.d_field;
std::cout << (int*)ch1 << ' ' << (int*)ch2 << ' ' << (int*)i_field
<< ' ' << (int*)d_field << ' ' << std::endl;
std::tie(ch1, ch2, i_field, d_field) = parse_padding<Padding2>();
std::cout << (int*)ch1 << ' ' << (int*)ch2 << ' ' << (int*)i_field
<< ' ' << (int*)d_field << ' ' << std::endl;
std::tie(ch1, ch2, i_field, d_field) = parse_padding<Padding3>();
std::cout << (int*)ch1 << ' ' << (int*)ch2 << ' ' << (int*)i_field
<< ' ' << (int*)d_field << ' ' << std::endl;
}

这是个老生常谈的问题,我随手糊的垃圾代码。

在C中, struct 和字段的顺序定义了结构体的内存布局,如果两个结构摆放顺序是相同的,内存布局也是相同的。

为了处理器便于取,用字段长度表示对齐属性:

所以,对齐属性2表示值只能存储在偶数地址里,1表示值可以存储在任何的地方

在我的 PC 运行这段代码:

16
16
24
0x7ffee669efb8 0x7ffee669efb9 0x7ffee669efbc 0x7ffee669efc0
0x7ffee669ed44 0x7ffee669ed45 0x7ffee669ed40 0x7ffee669ed48
0x7ffee669ed38 0x7ffee669ed40 0x7ffee669ed3c 0x7ffee669ed48

就这样。

padding = (align - (offset mod align)) mod align
aligned = offset + padding
= offset + ((align - (offset mod align)) mod align)

详情:https://en.wikipedia.org/wiki/Data_structure_alignment#Data_structure_padding

注意:https://stackoverflow.com/questions/10078283/how-sizeofarray-works-at-runtime VLA 会生成代码,在运行时求

Rust

struct A {
a: i32,
b: u64,
}
struct B {
a: i32,
b: u64,
}

与 C 不同,Rust 可能会选择不同的 align,保证所有成员是 align 整数倍即可。

Rust 不保证相对 struct 内存布局相同,不过你也可以 #[repr(C)]

#[repr(align(8))]
struct A32 {
a: u8,
b: u32,
c: u16,
}
let a32 = A32 {a: 1, b: 2, c: 3};
let ptr1 = &a32.a as * const u8;
let ptr2 = &a32.b as * const u32;
let ptr3 = &a32.c as * const u16;
println!("{:?} {:?} {:?}", ptr1, ptr2, ptr3);

本地运行结果:

0x7ffeedc0cef6 0x7ffeedc0cef0 0x7ffeedc0cef4

That‘s real magic!


https://en.wikipedia.org/wiki/Data_structure_alignment#Computing_padding