mirror of
https://github.com/nkbai/book.git
synced 2026-09-03 13:12:46 +08:00
Detail use of repr
This commit is contained in:
@@ -56,10 +56,10 @@ any combination or features is or is not enabled.
|
||||
|
||||
Additionally, Rust provides a number of automatically-set conditions you can
|
||||
use, such as `target_arch` to select different code based on architecture. For
|
||||
full details of the conditional compilation support, refer to the [Rust
|
||||
Reference].
|
||||
full details of the conditional compilation support, refer to the
|
||||
[conditional compilation] chapter of the Rust reference.
|
||||
|
||||
[Rust Reference]: https://doc.rust-lang.org/reference/conditional-compilation.html
|
||||
[conditional compilation]: https://doc.rust-lang.org/reference/conditional-compilation.html
|
||||
|
||||
The conditional compilation will only apply to the next statement or block. If
|
||||
a block can not be used in the current scope then then `cfg` attribute will
|
||||
@@ -218,6 +218,111 @@ with hardware (for example, writing a pointer to a buffer into a DMA peripheral
|
||||
register), and they are also used under the hood for all peripheral access
|
||||
crates to allow you to read and write memory-mapped registers.
|
||||
|
||||
## Packed and Aligned Types
|
||||
|
||||
In embedded C it is common to tell the compiler a variable must have a certain
|
||||
alignment or a struct must be packed rather than aligned, usually to meet
|
||||
specific hardware or protocol requirements.
|
||||
|
||||
In Rust this is controlled by the `repr` attribute on a struct or union. The
|
||||
default representation provides no guarantees of layout, so should not be used
|
||||
for code that interoperates with hardware or C. The compiler may re-order
|
||||
struct members or insert padding and the behaviour may change with future
|
||||
versions of Rust.
|
||||
|
||||
```rust
|
||||
struct Foo {
|
||||
x: u16,
|
||||
y: u8,
|
||||
z: u16,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let v = Foo { x: 0, y: 0, z: 0 };
|
||||
println!("{:p} {:p} {:p}", &v.x, &v.y, &v.z);
|
||||
}
|
||||
|
||||
// 0x7ffecb3511d0 0x7ffecb3511d4 0x7ffecb3511d2
|
||||
// Note ordering has been changed to y, z, y to improve packing.
|
||||
```
|
||||
|
||||
To ensure layouts that are interoperable with C, use `repr(C)`:
|
||||
|
||||
```rust
|
||||
#[repr(C)]
|
||||
struct Foo {
|
||||
x: u16,
|
||||
y: u8,
|
||||
z: u16,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let v = Foo { x: 0, y: 0, z: 0 };
|
||||
println!("{:p} {:p} {:p}", &v.x, &v.y, &v.z);
|
||||
}
|
||||
|
||||
// 0x7fffd0d84c60 0x7fffd0d84c62 0x7fffd0d84c64
|
||||
// Ordering is preserved and the layout will not change over time.
|
||||
// `z` is two-byte aligned so a byte of padding exists between `y` and `z`.
|
||||
```
|
||||
|
||||
To ensure a packed representation, use `repr(packed)`:
|
||||
|
||||
```rust
|
||||
#[repr(packed)]
|
||||
struct Foo {
|
||||
x: u16,
|
||||
y: u8,
|
||||
z: u16,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let v = Foo { x: 0, y: 0, z: 0 };
|
||||
// Unsafe is required to borrow a field of a packed struct.
|
||||
unsafe { println!("{:p} {:p} {:p}", &v.x, &v.y, &v.z) };
|
||||
}
|
||||
|
||||
// 0x7ffd33598490 0x7ffd33598492 0x7ffd33598493
|
||||
// No padding has been inserted between `y` and `z`, so now `z` is unaligned.
|
||||
```
|
||||
|
||||
Note that using `repr(packed)` also sets the alignment of the type to `1`.
|
||||
|
||||
Finally, to specify a specific alignment, use `repr(align(n))`, where `n` is
|
||||
the number of bytes to align to (and must be a power of two):
|
||||
|
||||
```rust
|
||||
#[repr(C)]
|
||||
#[repr(align(4096))]
|
||||
struct Foo {
|
||||
x: u16,
|
||||
y: u8,
|
||||
z: u16,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let v = Foo { x: 0, y: 0, z: 0 };
|
||||
let u = Foo { x: 0, y: 0, z: 0 };
|
||||
println!("{:p} {:p} {:p}", &v.x, &v.y, &v.z);
|
||||
println!("{:p} {:p} {:p}", &u.x, &u.y, &u.z);
|
||||
}
|
||||
|
||||
// 0x7ffec909a000 0x7ffec909a002 0x7ffec909a004
|
||||
// 0x7ffec909b000 0x7ffec909b002 0x7ffec909b004
|
||||
// The two instances `u` and `v` have been placed on 4096-byte alignments,
|
||||
// evidenced by the `000` at the end of their addresses.
|
||||
```
|
||||
|
||||
Note we can combine `repr(C)` with `repr(align(n))` to obtain an aligned and
|
||||
C-compatible layout. It is not permissible to combine `repr(align(n))` with
|
||||
`repr(packed)`, since `repr(packed)` sets the alignment to `1`. It is also not
|
||||
permissible for a `repr(packed)` type to contain a `repr(align(n))` type.
|
||||
|
||||
For further details on type layouts, refer to the [type layout] chapter of the
|
||||
Rust Reference.
|
||||
|
||||
[type layout]: https://doc.rust-lang.org/reference/type-layout.html
|
||||
|
||||
## Other Resources
|
||||
|
||||
* In this book: [A little C with your Rust](../interoperability/c-with-rust.md)
|
||||
|
||||
Reference in New Issue
Block a user