86 lines
2.6 KiB
Markdown
86 lines
2.6 KiB
Markdown
# C/C++ Headers
|
|
|
|
Under this section we discuss how to write the C/C++ header files that accompany the
|
|
Rust FFI library. The Rust-side counterpart of each topic is covered in
|
|
[FFI Function Signatures](ffi-function-signatures.md) and
|
|
[Allowed Data Types](allowed-data-types.md).
|
|
|
|
## Function Declaration Style
|
|
|
|
FFI functions must be exported under C names, that is, they must not go through the
|
|
C++ name mangling mechanism. In the generated C header file, you need to use the
|
|
`extern "C"` specifier, the `__cplusplus` macro and macro conditionals to import the
|
|
declarations correctly, for example:
|
|
|
|
```c++
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif // __cplusplus
|
|
|
|
CError WFStartup(void);
|
|
|
|
// More FFI functions omitted...
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
#endif // __cplusplus
|
|
```
|
|
|
|
## Parameter Declarations
|
|
|
|
A declaration of an exported FFI function in the C header file generally looks like
|
|
the following:
|
|
|
|
```c++
|
|
CError FBAdd(
|
|
OMRF_IN_PARAM_TY(uint32_t, in_a),
|
|
OMRF_IN_PARAM_TY(uint32_t, in_b),
|
|
OMRF_OUT_PARAM_TY(uint32_t, out_rv),
|
|
OMRF_OUT_PARAM_TY(bool, out_overflow));
|
|
```
|
|
|
|
## Required Header Files
|
|
|
|
The generated C/C++ header files must include the appropriate header files for the
|
|
types used in the declarations.
|
|
|
|
- In C, the `bool` type is provided by `<stddef.h>`. C++ supports `bool` natively
|
|
and does not need any header file.
|
|
- In C, the integer types are provided by `<stdint.h>`. In C++, they are provided
|
|
by `<cstdint>`.
|
|
- In C, the `uintptr_t` and `intptr_t` types are provided by `<stdint.h>`. In C++,
|
|
they are provided by `<cstdint>`.
|
|
- The floating-point types do not require any header file.
|
|
|
|
## Type Correspondences
|
|
|
|
The following table shows the correspondence between the Rust types that can cross
|
|
the FFI boundary directly (listed in [Allowed Data Types](allowed-data-types.md))
|
|
and their C/C++ counterparts. The left column lists the Rust type and the right
|
|
column lists the corresponding C/C++ type.
|
|
|
|
| Rust | C/C++ |
|
|
|------|-------|
|
|
| `bool` | `bool` |
|
|
| `f32` | `float` |
|
|
| `f64` | `double` |
|
|
| `i8` | `int8_t` |
|
|
| `i16` | `int16_t` |
|
|
| `i32` | `int32_t` |
|
|
| `i64` | `int64_t` |
|
|
| `u8` | `uint8_t` |
|
|
| `u16` | `uint16_t` |
|
|
| `u32` | `uint32_t` |
|
|
| `u64` | `uint64_t` |
|
|
| `usize` | `uintptr_t` |
|
|
| `isize` | `intptr_t` |
|
|
|
|
## The char Problem
|
|
|
|
For the Rust `char` type, the C/C++ header side uses `char32_t` as the parameter
|
|
type. Note that `char32_t` can hold any 32-bit unsigned integer, which is broader
|
|
than the set of valid Unicode scalar values carried by the Rust `char` type. The
|
|
Rust side is responsible for validating the incoming value; see
|
|
[The char Problem](allowed-data-types.md#the-char-problem) in
|
|
[Allowed Data Types](allowed-data-types.md).
|