You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust-C++ FFI中将C++枚举转换为Rust枚举?

解决Rust-C++ FFI枚举同步的便捷方案

不用自己写C++语法解析器,有几个现成的办法能实现枚举的自动同步:

1. 使用bindgen自动生成Rust绑定

bindgen是Rust生态中用来从C/C头文件自动生成FFI绑定的工具,能直接把C的枚举类转换成带数值关联的Rust枚举。

步骤:

  • 把C++枚举放到单独的头文件(比如code_enum.h):
#pragma once
enum class Code : int {
  Success = 0,
  Failed,

  Full = 10000,
  NotFound,
};
  • 在Rust项目的build.rs里配置bindgen:
use bindgen;
use std::path::PathBuf;

fn main() {
    // 生成绑定
    let bindings = bindgen::Builder::default()
        .header("code_enum.h")
        // 只生成Code枚举的绑定,避免冗余
        .allowlist_type("Code")
        .generate()
        .expect("无法生成绑定");

    // 把生成的绑定写入OUT_DIR目录
    let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("bindings.rs");
    bindings
        .write_to_file(out_path)
        .expect("无法写入绑定文件");
}
  • 在Cargo.toml里添加依赖:
[build-dependencies]
bindgen = "0.69"

每次构建Rust项目时,bindgen都会自动读取C头文件生成对应枚举,C端修改后重新构建即可同步。生成的Rust代码示例:

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Code {
    Success = 0,
    Failed = 1,
    Full = 10000,
    NotFound = 10001,
}

2. 利用C++编译器生成枚举值列表

借助C编译器的解析能力,把枚举的名称和数值导出到中间文件,再用Rust的build脚本读取生成枚举,完全不用自己处理C语法。

步骤:

  • 写一个辅助C++文件(enum_export.cpp)输出枚举键值对:
#include <iostream>
#include "code_enum.h"

int main() {
    std::cout << "Success=" << static_cast<int>(Code::Success) << "\n";
    std::cout << "Failed=" << static_cast<int>(Code::Failed) << "\n";
    std::cout << "Full=" << static_cast<int>(Code::Full) << "\n";
    std::cout << "NotFound=" << static_cast<int>(Code::NotFound) << "\n";
    return 0;
}
  • 在Rust的build.rs里编译并运行这个程序,生成Rust枚举:
use std::process::Command;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
    // 编译C++辅助程序
    Command::new("g++")
        .args(&["enum_export.cpp", "-o", "enum_export"])
        .status()
        .expect("编译辅助程序失败");

    // 运行程序获取枚举键值对
    let output = Command::new("./enum_export")
        .output()
        .expect("运行辅助程序失败");
    let enum_str = String::from_utf8(output.stdout).unwrap();

    // 生成Rust枚举代码
    let mut rust_enum = String::from("pub enum Code {\n");
    for line in enum_str.lines() {
        let parts: Vec<&str> = line.split('=').collect();
        let name = parts[0];
        let value = parts[1];
        rust_enum.push_str(&format!("  {} = {},\n", name, value));
    }
    rust_enum.push_str("}\n");

    // 写入到OUT_DIR目录,在Rust代码中引用
    let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("code_enum.rs");
    let mut file = File::create(out_path).expect("创建文件失败");
    file.write_all(rust_enum.as_bytes()).expect("写入文件失败");
}
  • 在Rust代码中通过include!(concat!(env!("OUT_DIR"), "/code_enum.rs"));引入生成的枚举。
    这种方法完全依赖C编译器的解析,不会出现语法错误,C端修改后重新构建Rust项目即可同步。

3. 用宏实现跨语言枚举定义

把枚举的核心定义放在一个共享的宏文件里,通过条件编译分别给C++和Rust生成对应的枚举代码,修改一次就能同步两边。

步骤:

  • 写一个共享宏文件(enum_defs.h):
#ifdef __cplusplus
#define ENUM_ENTRY(name, value) name = value,
#define DEFINE_ENUM(name) enum class name : int {
#define END_ENUM };
#else
#define ENUM_ENTRY(name, value) pub const #name: i32 = value;
#define DEFINE_ENUM(name) pub mod name {
#define END_ENUM }
#endif

DEFINE_ENUM(Code)
  ENUM_ENTRY(Success, 0)
  ENUM_ENTRY(Failed, 1)
  ENUM_ENTRY(Full, 10000)
  ENUM_ENTRY(NotFound, 10001)
END_ENUM
  • 在C++中直接包含这个头文件即可使用枚举;在Rust的build.rs里读取该文件,替换宏生成Rust枚举:
use std::fs::read_to_string;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
    let content = read_to_string("enum_defs.h").unwrap();
    let mut rust_enum = String::from("pub enum Code {\n");
    // 提取ENUM_ENTRY行生成枚举项
    for line in content.lines() {
        if line.contains("ENUM_ENTRY") {
            let parts: Vec<&str> = line.split(&['(', ',', ')'][..]).collect();
            let name = parts[1].trim();
            let value = parts[2].trim();
            rust_enum.push_str(&format!("  {} = {},\n", name, value));
        }
    }
    rust_enum.push_str("}\n");

    let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("code_enum.rs");
    let mut file = File::create(out_path).expect("创建文件失败");
    file.write_all(rust_enum.as_bytes()).expect("写入文件失败");
}

内容的提问来源于stack exchange,提问作者zRegle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 22:45:31