|
61 | 61 | //! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
|
62 | 62 | //! [`Global`] allocator with [`Layout::for_value(&*value)`].
|
63 | 63 | //!
|
| 64 | +//! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented |
| 65 | +//! as a single pointer and is also ABI-compatible with C pointers |
| 66 | +//! (i.e. the C type `T*`). This means that if you have extern "C" |
| 67 | +//! Rust functions that will be called from C, you can define those |
| 68 | +//! Rust functions using `Box<T>` types, and use `T*` as corresponding |
| 69 | +//! type on the C side. As an example, consider this C header which |
| 70 | +//! declares functions that create and destroy some kind of `Foo` |
| 71 | +//! value: |
64 | 72 | //!
|
| 73 | +//! ```c |
| 74 | +//! /* C header */ |
| 75 | +//! |
| 76 | +//! /* Returns ownership to the caller */ |
| 77 | +//! struct Foo* foo_new(void); |
| 78 | +//! |
| 79 | +//! /* Takes ownership from the caller; no-op when invoked with NULL */ |
| 80 | +//! void foo_delete(struct Foo*); |
| 81 | +//! ``` |
| 82 | +//! |
| 83 | +//! These two functions might be implemented in Rust as follows. Here, the |
| 84 | +//! `struct Foo*` type from C is translated to `Box<Foo>`, which captures |
| 85 | +//! the ownership constraints. Note also that the nullable argument to |
| 86 | +//! `foo_delete` is represented in Rust as `Option<Box<Foo>>`, since `Box<Foo>` |
| 87 | +//! cannot be null. |
| 88 | +//! |
| 89 | +//! ``` |
| 90 | +//! #[repr(C)] |
| 91 | +//! pub struct Foo; |
| 92 | +//! |
| 93 | +//! #[no_mangle] |
| 94 | +//! pub extern "C" fn foo_new() -> Box<Foo> { |
| 95 | +//! Box::new(Foo) |
| 96 | +//! } |
| 97 | +//! |
| 98 | +//! #[no_mangle] |
| 99 | +//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {} |
| 100 | +//! ``` |
| 101 | +//! |
| 102 | +//! Even though `Box<T>` has the same representation and C ABI as a C pointer, |
| 103 | +//! this does not mean that you can convert an arbitrary `T*` into a `Box<T>` |
| 104 | +//! and expect things to work. `Box<T>` values will always be fully aligned, |
| 105 | +//! non-null pointers. Moreover, the destructor for `Box<T>` will attempt to |
| 106 | +//! free the value with the global allocator. In general, the best practice |
| 107 | +//! is to only use `Box<T>` for pointers that originated from the global |
| 108 | +//! allocator. |
| 109 | +//! |
| 110 | +//! **Important.** At least at present, you should avoid using |
| 111 | +//! `Box<T>` types for functions that are defined in C but invoked |
| 112 | +//! from Rust. In those cases, you should directly mirror the C types |
| 113 | +//! as closely as possible. Using types like `Box<T>` where the C |
| 114 | +//! definition is just using `T*` can lead to undefined behavior, as |
| 115 | +//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198]. |
| 116 | +//! |
| 117 | +//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198 |
65 | 118 | //! [dereferencing]: ../../std/ops/trait.Deref.html
|
66 | 119 | //! [`Box`]: struct.Box.html
|
67 | 120 | //! [`Box<T>`]: struct.Box.html
|
|
0 commit comments