Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[第四章] 关于结构体对齐规则 #56

Closed
wucheng opened this issue Jan 11, 2019 · 10 comments
Closed

[第四章] 关于结构体对齐规则 #56

wucheng opened this issue Jan 11, 2019 · 10 comments
Labels
内容描述错误 内容描述有违事实 图示表意问题 书中图示的表意有问题 已修订 已经修订并提交给出版社 第四章 第四章 精选

Comments

@wucheng
Copy link

wucheng commented Jan 11, 2019

页码与行数

  • 第102页
  • 图4-8即下面描述

struct结构体对齐的规则,结构体A的长度是8个字节,但是内存布局不应该是图中所示a后面补充了1个字节,因为如果是这样,b的开始地址也不是4字节对齐的。

最终struct A是8个字节,是因为编译器对结构体成员进行了地址重排,先后顺序是b, c, a
如输出的其实地址所示

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=83128ce39b5e1b3ca58e77035f1111c5

文本或排版错误

@wucheng
Copy link
Author

wucheng commented Jan 11, 2019

116页,图4-11应该也是同样问题
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2984b495e92678a21a62f38bc53e41de

关于struct重排这个,搜了下rust文档有一些描述
https://doc.rust-lang.org/beta/nomicon/repr-rust.html

@ZhangHanDong
Copy link
Owner

@wucheng 感谢反馈。我看看先。

@ZhangHanDong ZhangHanDong added the 待确认 待确认的问题 label Jan 11, 2019
@honood
Copy link

honood commented Jan 13, 2019

116页,图4-11应该也是同样问题
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2984b495e92678a21a62f38bc53e41de

关于struct重排这个,搜了下rust文档有一些描述
https://doc.rust-lang.org/beta/nomicon/repr-rust.html

读 102 页的时候特别困惑。感谢你对这个问题的分析,并给出相关文档

@ZhangHanDong ZhangHanDong added this to the 第三次印刷 milestone Jan 13, 2019
@ZhangHanDong ZhangHanDong added 图示表意问题 书中图示的表意有问题 内容描述错误 内容描述有违事实 第四章 第四章 labels Jan 13, 2019
@yim7
Copy link

yim7 commented Jan 20, 2019

已经有读者反映就不需要重开 issue 了~

看这节时没理解找文档看了下,作者对于内存布局解释确实有错误,先不说 rust 的内存布局。

书中 102 页倒数第2行“那么对于成员 a 来说,它的对齐值为 MIN(4, 1), 即 1, 所以 a 需要补齐一个字节的空间”

成员 a 的 大小和对齐值都是1,所以它可以存在任何地址,是不需要补齐的。到下一个字段 b ,它需要偏移地址是 4 的倍数 ,所以需要填充 3 个字节。到字段 c , 因为加上 b 的大小的偏移,这时候的偏移已经是 4 的倍数了,所以 c 也不需要补齐。但是 struct 的对齐值等于其字段对齐值的最大值,也就是 4 ,所以要在 c 后面 补齐 2 个字节,使 struct 大小是 4 的倍数。这种布局有 5 个字节大小的内存浪费,如果我们调整字段顺序,只需要在最后补齐1个字节
https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=7571dcdbc0db81fa71a020c9acd21d6a

#[repr(C)]
struct A {
    b: u32,
    c: u16,
    a: u8,
}
fn main() {
    println!("{:?}", std::mem::size_of::<A>()); // 8
    let v = A { a: 1, b: 2, c: 3 };
    println!("&v {:p}", &v);
    println!("&v.b {:p}", &v.b);
    println!("&v.c {:p}", &v.c);
    println!("&v.a {:p}", &v.a);
}

以上说的是 repr(c) 的布局方式,rust 默认布局 struct 字段顺序是不确定的,编译器会进行优化调整字段顺序,以避免内存浪费的情况

参考
https://doc.rust-lang.org/reference/type-layout.html
https://doc.rust-lang.org/nomicon/repr-rust.html

@wucheng 感谢反馈。我看看先。
忘记@张老师了2333

@ZhangHanDong
Copy link
Owner

@yim7 感谢反馈。这部分还没抽出时间来确认,这周内看看。后续贴出更正内容。

@ZhangHanDong
Copy link
Owner

@wucheng @yim7

今天看了下这个问题,两位描述的是正确的。通过查看生成的LLVM IR可以直接看到补齐。

struct A {
    a: u8,
    b: u32,
    c: u16,
}

LLVM IR :

%A = type { [0 x i32], i32, [0 x i16], i16, [0 x i8], i8, [1 x i8] }

看得出来是重排了。给u8类型的a,分配了一个字节。

@wucheng nomicon的文档我是看过,估计是我自己后来忘记修改这块内容了,写书写到后面,有点麻木。再次感谢你们的反馈。

@ZhangHanDong ZhangHanDong removed the 待确认 待确认的问题 label Feb 10, 2019
@ZhangHanDong
Copy link
Owner

图4-8 修改为:

image

@ZhangHanDong
Copy link
Owner

@yim7

你这个例子应该修改为:

#![allow(unused)]
#[repr(C)]
struct A {
    a: u8,
    b: u32,
    c: u16,
    
}
fn main() {
    println!("{:?}", std::mem::size_of::<A>()); // 12
    let v = A { a: 1, b: 2, c: 3 };
}

才能看出没有重排的效果。是浪费了5个字节。

@ZhangHanDong
Copy link
Owner

图4-11修改:

image

@ZhangHanDong ZhangHanDong added the 已修订 已经修订并提交给出版社 label Feb 10, 2019
@ZhangHanDong
Copy link
Owner

图4-12修改为:

image

@ZhangHanDong ZhangHanDong pinned this issue Jun 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
内容描述错误 内容描述有违事实 图示表意问题 书中图示的表意有问题 已修订 已经修订并提交给出版社 第四章 第四章 精选
Projects
None yet
Development

No branches or pull requests

4 participants