
Rust 标准库中的 c_int 类型详解Rust 与 C FFI 交互中的平台相关整数类型【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust本文围绕 Rust 标准库文档library/core/src/ffi/c_int.md展开系统讲解core::ffi::c_int这一类型别名它对应 C 的signed int类型几乎在所有平台上等价于i32但在部分冷僻系统上可能是i16。读完后你将理解为什么 Rust 不提供固定的 C 类型别名会出错、c_int在标准库源码中如何按目标架构定义以及在extern CFFI 声明中应如何正确使用它。c_int 是什么对应 C 的 signed int原始文档对c_int的完整定义如下Equivalent to Cssigned int(int) type.This type will almost always be [i32], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [short]; some systems define it as an [i16], for example.也就是说c_int是 Rust 为 FFIForeign Function Interface外部函数接口场景提供的平台相关类型platform-specific types与 C 语言的标准int精确对齐。它的核心含义有两点几乎总是i32在 x86/x86_64、ARM、RISC-V 等主流目标平台上c_int就是i32但不保证是i32C 标准在技术上只要求int是“宽度至少与short相同的有符号整数”因此允许某些系统将其定义为i16。这正是c_int存在的价值所在——当 Rust 代码要与 C 函数交互时参数和返回值必须与 C 端的位宽、符号性完全一致否则就是未定义行为或静默的数据截断。直接使用i32在绝大多数平台没有问题但一旦目标平台是 AVR、MSP430 这类int为 16 位的嵌入式架构i32就会与 C 端 ABI 不匹配。使用c_int则能随目标平台自动切换保持类型层面的可移植性。源码实现c_int 如何在 core 中定义c_int的定义位于 library/core/src/ffi/primitives.rs。该文件的模块级注释说明了它的设计意图//! Defines primitive types that match Cs type definitions for FFI compatibility. //! //! This module is intentionally standalone to facilitate parsing when retrieving //! core C types.通过 type_alias! 宏展开类型别名c_int并不是直接书写的pub type c_int i32;而是通过同文件中的type_alias!宏生成primitives.rsmacro_rules! type_alias { { $Docfile:tt, $Alias:ident $Real:ty; $( $Cfg:tt )* } { #[doc include_str!($Docfile)] $( $Cfg )* #[stable(feature core_ffi_c, since 1.64.0)] pub type $Alias $Real; } }c_int与c_uint的声明为primitives.rstype_alias! { c_int.md, c_int c_int_definition::c_int; #[doc(cfg(true))] } type_alias! { c_uint.md, c_uint c_int_definition::c_uint; #[doc(cfg(true))] }可以看到三个要点#[doc include_str!(c_int.md)]rustdoc 显示的文档正是本文所讨论的 c_int.md 文件内容文档与类型实现分离存放#[stable(feature core_ffi_c, since 1.64.0)]c_int自 Rust 1.64.0 起稳定#[doc(cfg(true))]注释明确说明这是为了避免 rustdoc 显示 “Available on ...” 提示框——实现虽是目标相关的但每个目标都定义它因此文档上不做平台区分展示。按目标架构选择真实位宽真正决定c_int位宽的是私有的c_int_definition模块primitives.rsmod c_int_definition { crate::cfg_select! { any(target_arch avr, target_arch msp430) { pub(super) type c_int i16; pub(super) type c_uint u16; } _ { pub(super) type c_int i32; pub(super) type c_uint u32; } } }从源码结构看当前仓库中实际将c_int定义为i16的目标架构只有avr和msp430两类嵌入式架构其余所有目标一律回落到i32。c_uint始终与c_int等宽u16/u32这也与 c_uint.md 中“与int等宽的无符号整数”的文档描述一致。这种cfg_select!分派模式在 primitives.rs 中是通用的c_char第 40-136 行按架构与操作系统区分有符号性、c_long第 138-154 行64 位非 Windows 平台为i64其余为i32、c_double第 190-203 行AVR 上为f32均采用同一机制。c_int是其中分派规则最简单的一种。公开入口与稳定版本c_int通过 library/core/src/ffi/mod.rs 导出到core::ffimod primitives; #[stable(feature core_ffi_c, since 1.64.0)] pub use self::primitives::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong, c_ushort, };该模块的头部注释阐明了整个ffi模块的动机Platform-specific types, as defined by C. Code that interacts via FFI will almost certainly be using the base types provided by C, which arent nearly as nicely defined as Rusts primitive types. This module provides types which will match those defined by C, so that code that interacts with C will refer to the correct types.即C 的基本类型不如 Rust 原始类型“定义得那么干净”core::ffi提供一组与 C 定义精确匹配的类型确保跨语言调用时引用到正确的类型。std::ffi见 library/std/src/ffi/mod.rs则进一步将这些类型 re-export使std::ffi::c_int成为日常开发中最常见的引用路径。在 FFI 声明中正确使用 c_int在extern C块中声明 C 函数时凡是 C 端签名使用int的位置都应写c_int。标准库测试代码中就有现成示例library/coretests/tests/ptr.rs 声明了 C 标准库的printffn printf(_: *const ffi::c_char, ...) - ffi::c_int;printf在 C 中返回int因此 Rust 侧返回类型写作ffi::c_int而非i32——在 16 位int平台上两者并不相同。另一处佐证来自 library/coretests/tests/io/error.rs其注释指出“On all targets to date,RawOsErroris equivalent to ac_int”并用0 as core::ffi::c_int构造测试值。这与 library/core/src/io/error.rs 中RawOsError定义为c_int的实现相互印证——POSIXerrno与 C 的int同宽因此操作系统错误码在 core 层直接用c_int表达。c_int也是标准库大量 Unix 系统调用绑定的参数类型。以 library/std/src/sys/fd/unix.rs、library/std/src/sys/fs/unix.rs、library/std/src/sys/net/connection/socket/unix.rs 为代表的std系统层代码中c_int被高频用于open/close/fstat等返回文件描述符或错误码的原语绑定是std与操作系统 C 层对接的“基本货币”之一。此外core自身也用c_int声明了 C 运行时规范符号。library/core/src/ffi/mod.rs 中的runtime_symbols模块声明了memcmp、bcmp返回c_int等 canonical symbol用于 rustc 检查同符号名函数的定义一致性invalid_runtime_symbols_definitionslint。与相邻 C 类型的对照理解c_int的最佳方式是把它放在整套 C 类型族中对照。各类型的文档与实现均位于 library/core/src/ffi/ 目录Rust 类型对应 C 类型主流平台实际类型可能不同的情形c_schar/c_ucharsigned char/unsigned chari8/u8无固定 8 位c_short/c_ushortshort/unsigned shorti16/u16极冷僻平台上可能是更宽c_int/c_uintint/unsigned inti32/u32AVR、MSP430 上为i16/u16c_long/c_ulonglong/unsigned long平台相关64 位非 Windows 为i64/u64其余i32/u32c_longlong/c_ulonglonglong long/unsigned long longi64/u64无C 标准保证至少 64 位c_charchari8或u8有符号性随架构/OS 变化见 c_char 定义c_float/c_doublefloat/doublef32/f64AVR 上double为f32值得强调的是c_int与c_long的对比在 64 位 Linux 上c_long是i64而c_int是i32在 32 位或 Windows 平台上两者又都是i32。这就是为什么跨平台的 FFI 绑定不能想当然地用isize/i64替代 C 类型——只有这些平台相关别名才能保证语义跟随目标平台。实践建议与适用前提写extern C声明时优先用c_*别名当 C 头文件中的参数或返回值是int、unsigned int时直接写c_int/c_uint。对std目标而言二者与i32/u32完全等价但c_int的表达意图更明确且能在嵌入式目标上自动适配。不要用c_int表达 Rust 内部逻辑宽度c_int的存在目的是匹配 C ABI如果某处整数宽度是由 Rust 自身语义决定如循环计数应使用i32或isize。版本前提core::ffi模块基础稳定于 1.30.0c_void、CStr等而c_int等 C 基本类型别名族稳定于 1.64.0feature:core_ffi_cc_size_t/c_ptrdiff_t/c_ssize_t仍为 unstablefeature:c_size_t见 primitives.rs需要 nightly 与-Zunstable-options/feature gate 才能使用。冷僻目标验证如果你的代码会移植到 AVR/MSP430 之外的新目标建议在 library/coretests/tests/ 中为 FFI 绑定补充针对实际目标编译的测试参照 ptr.rs 中对printf签名的断言写法以确认c_int与 C 工具链的一致性。小结c_int虽然只是一个类型别名却浓缩了 Rust FFI 设计的核心权衡Rust 原始类型i32语义固定而 C 基本类型的宽度由平台决定。core::ffi::c_int通过 primitives.rs 中type_alias!宏与cfg_select!目标分派让 Rust 代码在任何目标上都能拿到与 Cint位宽、符号性一致的整数类型——主流平台是i32AVR 与 MSP430 上则是i16。理解这一机制后你可以放心地用它编写可移植的extern C绑定而不必在每一处手动核对目标平台的 ABI。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考