Interoperability with C/C++

This topic provides information on the interoperability of Rust with C/C++.

Within Rust, the layout of a type involves a type’s size, alignment, and relative offsets of its fields. Furthermore, aggregate types (such as structures) have a representation that specifies how the compiler computes the layout for the type. By default, Rust uses its own "Rust" representation. More information on the Rust representation can be found here.

In addition to the default Rust representation, it also supports C representation by applying the #[repr(C)] attribute to user-defined aggregate types. The C representation is meant to create types that are interoperable with the C language, where the order, size, and alignment of fields are what would be expected from C or C++.

By default, structures in C/C++ on AIX follow what is known as power alignment rule. This rule instructs that structures with a floating-point type that is greater than 4-bytes, as the recursively first field (at offset 0), modify the layout of subsequent fields of the associated structs to use an alignment value where the floating-point type is aligned on a 4-byte boundary.

For more information on the power alignment rule, see documentation on Using alignment modes and Alignment of aggregates.

The power alignment rule for structs needed for C compatibility is unimplemented within repr(C) in the Rust compiler. Therefore, a warning message is displayed in the case when such structs are encountered.

The following example displays a structure that is annotated with repr(C):
#[repr(C)]
pub struct Floats {
    a: f64,
    b: u8,
    c: f64,
}
This structure displays the following warning message:
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
  --> <source>:5:3
   |
 5 |   c: f64,
   |   ^^^^^^
   |
   = note: `#[warn(uses_power_alignment)]` on by default
The power alignment rule specifies that the struct displayed in the example should have the following alignment:
  • a is aligned at offset 0

  • b is aligned at offset 8

  • c is aligned at offset 12

The Rust compiler currently aligns c at offset 16.

This warning is turned on in the compiler by default. However, this can be turned off by writing the following Rust attribute on the affected structs:

#[allow(uses_power_alignment)]

As a temporary solution to allow structs to conform with the power alignment rule, the packed(1) Rust representation attribute can be added to structs annotated with the #[repr(C)] attribute.

In addition to appending this attribute to affected structs, manually padding the structure is required internally to align each field after modifying their alignment requirements according to the power alignment rule. Inserting tail padding is also required to ensure the size of the structure is correct for the overall alignment requirement of the whole structure.

The aforementioned struct can be written in the following way to follow the power alignment rule:

#[repr(C, packed(1))]
pub struct Floats {
    a: f64,
    b: u8,
    p1: u8,
    p2: u8,
    p3: u8,
    c: f64,
    p4: u8,
    p5: u8,
    p6: u8,
    p7: u8,
}

In this structure, c is aligned at offset 12.