Expand description
§abienum - underlying types for C enums
Attempts to define the implicit underlying types of C and C++ enums, when compiled via the cc crate using default settings.
That is, enums that follow any of these styles:
enum Test { Hello = 1 };
typedef enum { Hello = 1 } Test;
typedef enum Test { Hello = 1 } Test;
typedef enum _Test { Hello = 1 } Test;Would presumably be FFI-compatible with the following Rust type:
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)] pub struct Test(abienum::c_enum_u7);
impl Test { pub const Hello : Test = Test(1 as _); }You are expected to use the c_enum_* with the smallest compatible range — e.g. c_enum_u7 over c_enum_u8 or c_enum_i8.
§Caveats
The underlying type of enums is implementation specific, to the point of being potentially finicky in practice.
-
Compilers may disagree on enum size. For example, ARM delegates type selection to the platform ABI, which leads to Clang and GCC disagreeing on enum size for unknown/none, where no platform ABI is specified or agreed upon. If using the
cccrate, prefer a globalCC=...over.compiler("..."). If linking against prebuilt libraries, specify the same compiler as was used for said libraries viaCC=... -
Compilers provide flags controlling enum size, such as
-f[no-]short-enums[clang, gcc]. If you need these, prefer a globalCFLAGS=...over.flag("..."). -
Compilers may provide extensions controlling enum size, such as
__attribute__((packed))or#pragmas. You’re completely on your own for those. I recommend a lot ofstatic_asserts on the C++ side andconst _ : () = assert!(...);s on the Rust side. Good luck. -
Compilers may or may not actually respect the flags, attributes, and pragmas specified. E.g. LLVM seems to ignore them on Win32 despite parsing them (llvm/llvm-project #70607)
-
Type selection beyond the basics (e.g. involving potentially typed expressions that depend on previous enumerands) is enough of a potential mess that I haven’t tackled it. See also these C23 proposals:
§Alternatives
C++11 (and perhaps C23?) provides syntax to explicitly control the underlying type of enums, which — assuming you can sanely modify the C/C++ — I strongly recommend over resorting to this crate’s nonsense:
enum Test : int { Hello = 1 };#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)] pub struct Test(core::ffi::c_int);
impl Test { pub const Hello : Test = Test(1 as _); }If you’re stuck in earlier versions of C or C++, the old “force dword” trick will at least get the size right (signedness may still vary):
typedef enum _D3DLIGHTTYPE {
D3DLIGHT_POINT = 1,
D3DLIGHT_SPOT = 2,
D3DLIGHT_DIRECTIONAL = 3,
D3DLIGHT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */
} D3DLIGHTTYPE;#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)] pub struct D3DLIGHTTYPE(i32);
pub const D3DLIGHT_POINT : D3DLIGHTTYPE = D3DLIGHTTYPE(1);
pub const D3DLIGHT_SPOT : D3DLIGHTTYPE = D3DLIGHTTYPE(2);
pub const D3DLIGHT_DIRECTIONAL : D3DLIGHTTYPE = D3DLIGHTTYPE(3);
// const D3DLIGHT_FORCE_DWORD : D3DLIGHTTYPE = D3DLIGHTTYPE(0x7fffffff); // impl detailLicense
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Type Aliases§
- c_
enum_ i8 enum { Min = -128, Max = 127 }’s underlying type.
Frequently a larger type thani8, such asc_int≈i32.
- c_
enum_ i16 enum { Min = -32768, Max = 32767 }’s underlying type.
Frequently a larger type thani16, such asc_int≈i32.
- c_
enum_ i32 enum { Min = -2147483648, Max = 2147483647 }’s underlying type.
Typicallyc_int.
- c_
enum_ i64 enum { Min = -263, Max = 263-1 }’s underlying type.
Frequentlyc_int, even when that loses information truncating to 32 bits!
- c_
enum_ u7 enum { Min = 0, Max = 127 }’s underlying type.
Frequently a larger type thani8, such as a 32-bitc_intorc_uint.
- c_
enum_ u8 enum { Min = 0, Max = 255 }’s underlying type.
Frequently a larger type thanu8, such as a 32-bitc_intorc_uint.
- c_
enum_ u15 enum { Min = 0, Max = 32767 }’s underlying type.
Frequently a larger type thani16, such as a 32-bitc_intorc_uint.
- c_
enum_ u16 enum { Min = 0, Max = 65535 }’s underlying type.
Frequently a larger type thanu16, such as a 32-bitc_intorc_uint.
- c_
enum_ u31 enum { Min = 0, Max = 2147483647 }’s underlying type.
Typicallyc_int(Windows) orc_uint(*nix).
- c_
enum_ u32 enum { Min = 0, Max = 4294967295 }’s underlying type.
Frequentlyc_int(Windows), even when that truncates 4294967295 to -1.
- c_
enum_ u63 enum { Min = 0, Max = 263-1 }’s underlying type.
Frequentlyc_int, even when that loses information truncating to 32 bits!
- c_
enum_ u64 enum { Min = 0, Max = 264-1 }’s underlying type.
Frequentlyc_int, even when that loses information truncating to 32 bits!