RUST结构体内存分布研究

为什么要验证结构体内存分布 内存分布是一个比较有意思的话题。 C语言的结构体,内存分布是按照成员顺序进行排列的。虽然结构体中实际的成员分布会受字节对齐方式的影响,但是成员的顺序是不会更改的。 构造一个结构体Demo,查看内存分布情况。 #include <stdio.h> #pragma pack

为什么要验证结构体内存分布

内存分布是一个比较有意思的话题。

C语言的结构体,内存分布是按照成员顺序进行排列的。虽然结构体中实际的成员分布会受字节对齐方式的影响,但是成员的顺序是不会更改的。

构造一个结构体Demo,查看内存分布情况。

#include <stdio.h>

#pragma pack(4)
struct Demo {
	short a;
	int b;
	char c;
};
#pragma pack()

int main() {
	struct Demo demo = { 0 };

	printf("size: %lu\n", sizeof(demo));
	printf("Mem Addr:\n");
	printf("a: %p, b: %p, c: %p\n", &demo.a, &demo.b, &demo.c);
}

如果按照4字节对齐,则结构体占用的空间为12字节,内存分布如下(.表示填充)

1

2

3

4

5

6

7

8

9

10

11

12

a

a

.

.

b

b

b

b

c

.

.

.

如果按照2字节对齐,则占用空间为8字节,内存分布如下

1

2

3

4

5

6

7

8

a

a

b

b

b

b

c

.

如果按照1字节对齐,则占用空间为7字节,内存分布省略。

RUST结构体的内存分布

上面的例子,我们使用RUST语言写一遍,代码如下

use std::mem::{size_of, aligh_of};

struct Demo {
	pub a: i16,
	pub b: i32,
	pub c: i8
}

fn main() {
	let demo = Demo { a: 0, b: 0, c: 0 };

	println!("size: {}", size_of::<Demo>());
	println!("align: {}", aligh_of::<Demo>());
	println!("Mem Addr:");
	println!("a: 0x{:x}, a: 0x{:x}, a: 0x{:x}",
			 &demo.a as *const i16 as usize,
			 &demo.b as *const i32 as usize,
			 &demo.c as *const i8 as usize);
}

不指定任何编译选项直接编译并运行。
结构体采用4字节对齐,但是结构体占用空间为8字节,和C语言写的结构体有差异,查看内存分布如下

1

2

3

4

5

6

7

8

b

b

b

b

a

a

c

.

可以看到,成员b的内存分布,居然在a的前面,和我们定义结构体的顺序有差异。
由此可以看到,rust编译器会对结构体成员的分布进行优化,尽可能节省空间。
RUST这样做事得益于其设计理念默认是不允许代码直接操作到裸指针,因此可以尽情优化内存排布。

当然RUST也支持内存分布按照C语言的规则来进行,需要对其使用repr过程宏修饰,其标准类型最好也要修改下,rust提供了libc这个crate,可以使用C语言的标准类型。

use std::mem::{size_of, aligh_of};
use libc::{c_short, c_int, c_char};

#[repr(C)]
struct Demo {
	pub a: c_short,
	pub b: c_int,
	pub c: c_char
}

fn main() {
	let demo = Demo { a: 0, b: 0, c: 0 };

	println!("size: {}", size_of::<Demo>());
	println!("align: {}", aligh_of::<Demo>());
	println!("Mem Addr:");
	println!("a: 0x{:x}, a: 0x{:x}, a: 0x{:x}",
			 &demo.a as *const c_short as usize,
			 &demo.b as *const c_int as usize,
			 &demo.c as *const c_char as usize);

此时再运行一下,查看结果。
结构体采用4字节对齐,结构体占用空间是12字节,内存排布如下

1

2

3

4

5

6

7

8

9

10

11

12

a

a

.

.

b

b

b

b

c

.

.

.

此时和C语言定义的结构体的内存分布就一样了。

我们也可以指定字节对齐方式为2字节对齐

#[repr(C, aligh(2))]
struct Demo {
	pub a: c_short,
	pub b: c_int,
	pub c: c_char
}

此时得到的结果和C语言定义的2字节对齐的结构体是一样的。

LICENSED UNDER CC BY-NC-SA 4.0
评论