1# Tips for embedded C developers
2
3This chapter collects a variety of tips that might be useful to experienced
4embedded C developers looking to start writing Rust. It will especially
5highlight how things you might already be used to in C are different in Rust.
6
7## Preprocessor
8
9In embedded C it is very common to use the preprocessor for a variety of
10purposes, such as:
11
12* Compile-time selection of code blocks with `#ifdef`
13* Compile-time array sizes and computations
14* Macros to simplify common patterns (to avoid function call overhead)
15
16In Rust there is no preprocessor, and so many of these use cases are addressed
17differently. In the rest of this section we cover various alternatives to
18using the preprocessor.
19
20### Compile-Time Code Selection
21
22The closest match to `#ifdef ... #endif` in Rust are [Cargo features]. These
23are a little more formal than the C preprocessor: all possible features are
24explicitly listed per crate, and can only be either on or off. Features are
25turned on when you list a crate as a dependency, and are additive: if any crate
26in your dependency tree enables a feature for another crate, that feature will
27be enabled for all users of that crate.
28
29[Cargo features]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
30
31For example, you might have a crate which provides a library of signal
32processing primitives. Each one might take some extra time to compile or
33declare some large table of constants which you'd like to avoid. You could
34declare a Cargo feature for each component in your `Cargo.toml`:
35
36```toml
37[features]
38FIR = []
39IIR = []
40```
41
42Then, in your code, use `#[cfg(feature="FIR")]` to control what is included.
43
44```rust
45/// In your top-level lib.rs
46
47#[cfg(feature="FIR")]
48pub mod fir;
49
50#[cfg(feature="IIR")]
51pub mod iir;
52```
53
54You can similarly include code blocks only if a feature is _not_ enabled, or if
55any combination of features are or are not enabled.
56
57Additionally, Rust provides a number of automatically-set conditions you can
58use, such as `target_arch` to select different code based on architecture. For
59full details of the conditional compilation support, refer to the
60[conditional compilation] chapter of the Rust reference.
61
62[conditional compilation]: https://doc.rust-lang.org/reference/conditional-compilation.html
63
64The conditional compilation will only apply to the next statement or block. If
65a block can not be used in the current scope then the `cfg` attribute will
66need to be used multiple times.  It's worth noting that most of the time it is
67better to simply include all the code and allow the compiler to remove dead
68code when optimising: it's simpler for you and your users, and in general the
69compiler will do a good job of removing unused code.
70
71### Compile-Time Sizes and Computation
72
73Rust supports `const fn`, functions which are guaranteed to be evaluable at
74compile-time and can therefore be used where constants are required, such as
75in the size of arrays. This can be used alongside features mentioned above,
76for example:
77
78```rust
79const fn array_size() -> usize {
80    #[cfg(feature="use_more_ram")]
81    { 1024 }
82    #[cfg(not(feature="use_more_ram"))]
83    { 128 }
84}
85
86static BUF: [u32; array_size()] = [0u32; array_size()];
87```
88
89These are new to stable Rust as of 1.31, so documentation is still sparse. The
90functionality available to `const fn` is also very limited at the time of
91writing; in future Rust releases it is expected to expand on what is permitted
92in a `const fn`.
93
94### Macros
95
96Rust provides an extremely powerful [macro system]. While the C preprocessor
97operates almost directly on the text of your source code, the Rust macro system
98operates at a higher level. There are two varieties of Rust macro: _macros by
99example_ and _procedural macros_. The former are simpler and most common; they
100look like function calls and can expand to a complete expression, statement,
101item, or pattern. Procedural macros are more complex but permit extremely
102powerful additions to the Rust language: they can transform arbitrary Rust
103syntax into new Rust syntax.
104
105[macro system]: https://doc.rust-lang.org/book/ch19-06-macros.html
106
107In general, where you might have used a C preprocessor macro, you probably want
108to see if a macro-by-example can do the job instead. They can be defined in
109your crate and easily used by your own crate or exported for other users. Be
110aware that since they must expand to complete expressions, statements, items,
111or patterns, some use cases of C preprocessor macros will not work, for example
112a macro that expands to part of a variable name or an incomplete set of items
113in a list.
114
115As with Cargo features, it is worth considering if you even need the macro. In
116many cases a regular function is easier to understand and will be inlined to
117the same code as a macro. The `#[inline]` and `#[inline(always)]` [attributes]
118give you further control over this process, although care should be taken here
119as well — the compiler will automatically inline functions from the same crate
120where appropriate, so forcing it to do so inappropriately might actually lead
121to decreased performance.
122
123[attributes]: https://doc.rust-lang.org/reference/attributes.html#inline-attribute
124
125Explaining the entire Rust macro system is out of scope for this tips page, so
126you are encouraged to consult the Rust documentation for full details.
127
128## Build System
129
130Most Rust crates are built using Cargo (although it is not required). This
131takes care of many difficult problems with traditional build systems. However,
132you may wish to customise the build process. Cargo provides [`build.rs`
133scripts] for this purpose. They are Rust scripts which can interact with the
134Cargo build system as required.
135
136[`build.rs` scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
137
138Common use cases for build scripts include:
139
140* provide build-time information, for example statically embedding the build
141  date or Git commit hash into your executable
142* generate linker scripts at build time depending on selected features or other
143  logic
144* change the Cargo build configuration
145* add extra static libraries to link against
146
147At present there is no support for post-build scripts, which you might
148traditionally have used for tasks like automatic generation of binaries from
149the build objects or printing build information.
150
151### Cross-Compiling
152
153Using Cargo for your build system also simplifies cross-compiling. In most
154cases it suffices to tell Cargo `--target thumbv6m-none-eabi` and find a
155suitable executable in `target/thumbv6m-none-eabi/debug/myapp`.
156
157For platforms not natively supported by Rust, you will need to build `libcore`
158for that target yourself. On such platforms, [Xargo] can be used as a stand-in
159for Cargo which automatically builds `libcore` for you.
160
161[Xargo]: https://github.com/japaric/xargo
162
163## Iterators vs Array Access
164
165In C you are probably used to accessing arrays directly by their index:
166
167```c
168int16_t arr[16];
169int i;
170for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++) {
171    process(arr[i]);
172}
173```
174
175In Rust this is an anti-pattern: indexed access can be slower (as it needs to
176be bounds checked) and may prevent various compiler optimisations. This is an
177important distinction and worth repeating: Rust will check for out-of-bounds
178access on manual array indexing to guarantee memory safety, while C will
179happily index outside the array.
180
181Instead, use iterators:
182
183```rust,ignore
184let arr = [0u16; 16];
185for element in arr.iter() {
186    process(*element);
187}
188```
189
190Iterators provide a powerful array of functionality you would have to implement
191manually in C, such as chaining, zipping, enumerating, finding the min or max,
192summing, and more. Iterator methods can also be chained, giving very readable
193data processing code.
194
195See the [Iterators in the Book] and [Iterator documentation] for more details.
196
197[Iterators in the Book]: https://doc.rust-lang.org/book/ch13-02-iterators.html
198[Iterator documentation]: https://doc.rust-lang.org/core/iter/trait.Iterator.html
199
200## References vs Pointers
201
202In Rust, pointers (called [_raw pointers_]) exist but are only used in specific
203circumstances, as dereferencing them is always considered `unsafe` -- Rust
204cannot provide its usual guarantees about what might be behind the pointer.
205
206[_raw pointers_]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
207
208In most cases, we instead use _references_, indicated by the `&` symbol, or
209_mutable references_, indicated by `&mut`. References behave similarly to
210pointers, in that they can be dereferenced to access the underlying values, but
211they are a key part of Rust's ownership system: Rust will strictly enforce that
212you may only have one mutable reference _or_ multiple non-mutable references to
213the same value at any given time.
214
215In practice this means you have to be more careful about whether you need
216mutable access to data: where in C the default is mutable and you must be
217explicit about `const`, in Rust the opposite is true.
218
219One situation where you might still use raw pointers is interacting directly
220with hardware (for example, writing a pointer to a buffer into a DMA peripheral
221register), and they are also used under the hood for all peripheral access
222crates to allow you to read and write memory-mapped registers.
223
224## Volatile Access
225
226In C, individual variables may be marked `volatile`, indicating to the compiler
227that the value in the variable may change between accesses. Volatile variables
228are commonly used in an embedded context for memory-mapped registers.
229
230In Rust, instead of marking a variable as `volatile`, we use specific methods
231to perform volatile access: [`core::ptr::read_volatile`] and
232[`core::ptr::write_volatile`]. These methods take a `*const T` or a `*mut T`
233(_raw pointers_, as discussed above) and perform a volatile read or write.
234
235[`core::ptr::read_volatile`]: https://doc.rust-lang.org/core/ptr/fn.read_volatile.html
236[`core::ptr::write_volatile`]: https://doc.rust-lang.org/core/ptr/fn.write_volatile.html
237
238For example, in C you might write:
239
240```c
241volatile bool signalled = false;
242
243void ISR() {
244    // Signal that the interrupt has occurred
245    signalled = true;
246}
247
248void driver() {
249    while(true) {
250        // Sleep until signalled
251        while(!signalled) { WFI(); }
252        // Reset signalled indicator
253        signalled = false;
254        // Perform some task that was waiting for the interrupt
255        run_task();
256    }
257}
258```
259
260The equivalent in Rust would use volatile methods on each access:
261
262```rust,ignore
263static mut SIGNALLED: bool = false;
264
265#[interrupt]
266fn ISR() {
267    // Signal that the interrupt has occurred
268    // (In real code, you should consider a higher level primitive,
269    //  such as an atomic type).
270    unsafe { core::ptr::write_volatile(&mut SIGNALLED, true) };
271}
272
273fn driver() {
274    loop {
275        // Sleep until signalled
276        while unsafe { !core::ptr::read_volatile(&SIGNALLED) } {}
277        // Reset signalled indicator
278        unsafe { core::ptr::write_volatile(&mut SIGNALLED, false) };
279        // Perform some task that was waiting for the interrupt
280        run_task();
281    }
282}
283```
284
285A few things are worth noting in the code sample:
286  * We can pass `&mut SIGNALLED` into the function requiring `*mut T`, since
287    `&mut T` automatically converts to a `*mut T` (and the same for `*const T`)
288  * We need `unsafe` blocks for the `read_volatile`/`write_volatile` methods,
289    since they are `unsafe` functions. It is the programmer's responsibility
290    to ensure safe use: see the methods' documentation for further details.
291
292It is rare to require these functions directly in your code, as they will
293usually be taken care of for you by higher-level libraries. For memory mapped
294peripherals, the peripheral access crates will implement volatile access
295automatically, while for concurrency primitives there are better abstractions
296available (see the [Concurrency chapter]).
297
298[Concurrency chapter]: ../concurrency/index.md
299
300## Packed and Aligned Types
301
302In embedded C it is common to tell the compiler a variable must have a certain
303alignment or a struct must be packed rather than aligned, usually to meet
304specific hardware or protocol requirements.
305
306In Rust this is controlled by the `repr` attribute on a struct or union. The
307default representation provides no guarantees of layout, so should not be used
308for code that interoperates with hardware or C. The compiler may re-order
309struct members or insert padding and the behaviour may change with future
310versions of Rust.
311
312```rust
313struct Foo {
314    x: u16,
315    y: u8,
316    z: u16,
317}
318
319fn main() {
320    let v = Foo { x: 0, y: 0, z: 0 };
321    println!("{:p} {:p} {:p}", &v.x, &v.y, &v.z);
322}
323
324// 0x7ffecb3511d0 0x7ffecb3511d4 0x7ffecb3511d2
325// Note ordering has been changed to x, z, y to improve packing.
326```
327
328To ensure layouts that are interoperable with C, use `repr(C)`:
329
330```rust
331#[repr(C)]
332struct Foo {
333    x: u16,
334    y: u8,
335    z: u16,
336}
337
338fn main() {
339    let v = Foo { x: 0, y: 0, z: 0 };
340    println!("{:p} {:p} {:p}", &v.x, &v.y, &v.z);
341}
342
343// 0x7fffd0d84c60 0x7fffd0d84c62 0x7fffd0d84c64
344// Ordering is preserved and the layout will not change over time.
345// `z` is two-byte aligned so a byte of padding exists between `y` and `z`.
346```
347
348To ensure a packed representation, use `repr(packed)`:
349
350```rust
351#[repr(packed)]
352struct Foo {
353    x: u16,
354    y: u8,
355    z: u16,
356}
357
358fn main() {
359    let v = Foo { x: 0, y: 0, z: 0 };
360    // Unsafe is required to borrow a field of a packed struct.
361    unsafe { println!("{:p} {:p} {:p}", &v.x, &v.y, &v.z) };
362}
363
364// 0x7ffd33598490 0x7ffd33598492 0x7ffd33598493
365// No padding has been inserted between `y` and `z`, so now `z` is unaligned.
366```
367
368Note that using `repr(packed)` also sets the alignment of the type to `1`.
369
370Finally, to specify a specific alignment, use `repr(align(n))`, where `n` is
371the number of bytes to align to (and must be a power of two):
372
373```rust
374#[repr(C)]
375#[repr(align(4096))]
376struct Foo {
377    x: u16,
378    y: u8,
379    z: u16,
380}
381
382fn main() {
383    let v = Foo { x: 0, y: 0, z: 0 };
384    let u = Foo { x: 0, y: 0, z: 0 };
385    println!("{:p} {:p} {:p}", &v.x, &v.y, &v.z);
386    println!("{:p} {:p} {:p}", &u.x, &u.y, &u.z);
387}
388
389// 0x7ffec909a000 0x7ffec909a002 0x7ffec909a004
390// 0x7ffec909b000 0x7ffec909b002 0x7ffec909b004
391// The two instances `u` and `v` have been placed on 4096-byte alignments,
392// evidenced by the `000` at the end of their addresses.
393```
394
395Note we can combine `repr(C)` with `repr(align(n))` to obtain an aligned and
396C-compatible layout. It is not permissible to combine `repr(align(n))` with
397`repr(packed)`, since `repr(packed)` sets the alignment to `1`. It is also not
398permissible for a `repr(packed)` type to contain a `repr(align(n))` type.
399
400For further details on type layouts, refer to the [type layout] chapter of the
401Rust Reference.
402
403[type layout]: https://doc.rust-lang.org/reference/type-layout.html
404
405## Other Resources
406
407* In this book:
408    * [A little C with your Rust](../interoperability/c-with-rust.md)
409    * [A little Rust with your C](../interoperability/rust-with-c.md)
410* [The Rust Embedded FAQs](https://docs.rust-embedded.org/faq.html)
411* [Rust Pointers for C Programmers](http://blahg.josefsipek.net/?p=580)
412* [I used to use pointers - now what?](https://github.com/diwic/reffers-rs/blob/master/docs/Pointers.md)
413