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

使用autocxx实现Rust与C++交互时获取值异常问题排查

问题描述

在将Rust代码嵌入C环境时遇到值异常:C端调用board.columns()输出预期值7,但通过autocxx传递Board对象到Rust后,Rust端获取的board.columns()和传入的length都是随机无效值,需排查错误原因。

相关代码

CMakeLists.txt

cmake_minimum_required(VERSION 3.11.0)
project(4Gewinnt VERSION 0.2.1)

include(CTest)
enable_testing()

add_library(ai_lib SHARED
    src/mirror_ai.cpp
)

# 引入Rust项目作为外部依赖
include(ExternalProject)

ExternalProject_Add(
    rust_example
    SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rust_example"
    BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rust_example"
    CONFIGURE_COMMAND ""
    BUILD_COMMAND cargo build --release
    INSTALL_COMMAND ""
    BUILD_BYPRODUCTS "${CMAKE_CURRENT_SOURCE_DIR}/rust_example/target/release/librust_example.so" # 根据需要调整库名
)

# 指定C++可执行目标
add_executable(VierGewinnt
    src/main.cpp
    src/base_entity.cpp
    src/board.cpp
    src/color.cpp
    src/difficulty.cpp
    src/easy_ai.cpp
    src/game.cpp
    src/hard_ai.cpp
    src/medium_ai.cpp
    src/player.cpp
)

target_link_libraries(VierGewinnt PRIVATE ai_lib)

# 添加构建Rust项目的自定义命令
add_custom_command(TARGET VierGewinnt POST_BUILD
    COMMAND cargo build --release
    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/rust_example"
    COMMENT "构建Rust项目"
)

# 链接Rust库
add_dependencies(VierGewinnt rust_example)
target_link_libraries(VierGewinnt PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/rust_example/target/release/librust_example.so") # 根据需要调整库名

# 包含目录
target_include_directories(VierGewinnt PRIVATE
    include
    lib
    "${CMAKE_CURRENT_SOURCE_DIR}/rust_example/include"
)

target_compile_features(VierGewinnt PUBLIC cxx_std_20)
target_compile_options(VierGewinnt PUBLIC -Wall -pedantic -Wextra)

rust.hpp

#pragma once
#include "board.hpp"

extern "C" {
Column rust_main(Board board, int length);
}

medium_ai.cpp

#include "medium_ai.hpp"
#include "rust.hpp"
#include <iostream>

Column MediumAI::choose_slot(const Board &board) {
  int length = board.columns();
  std::cout << "[cpp] board.columns: " << length << std::endl;
  Column result = rust_main(board, length);

  return result;
}

lib.rs

use autocxx::prelude::*;
use rand::Rng;

include_cpp! {
    #include "board.hpp"
    #include "column.hpp"
    safety!(unsafe_ffi)
    generate!("Board")
    generate!("Column")
}

#[no_mangle]
pub extern "C" fn rust_main(board: ffi::Board, length: i32) -> UniquePtr<ffi::Column> {
    println!(
        "[rust] board.columns: {}, length: {}",
        board.columns(),
        length
    ); // --> 两者均为随机无效值

    let mut rand_slot: usize;
    let mut rng = rand::thread_rng();

    loop {
        rand_slot = rng.gen_range(0..=board.columns());
        println!("[rust] rand_slot: {}", rand_slot);

        if !board.is_full(ffi::Column::new(rand_slot).within_unique_ptr()) {
            break;
        }
    }

    let column = ffi::Column::new(rand_slot).within_unique_ptr();
    column
}

错误原因及解决方法

1. 参数传递的ABI不匹配

autocxx生成的Rust类型ffi::Board并非直接对应C++的Board值类型,按值传递Board会因内存布局、ABI差异导致Rust端解析错误,出现随机值。

解决方法:
传递Board指针而非值,保持两端类型匹配:

  • 修改rust.hpp:
    extern "C" {
    Column rust_main(const Board* board, int length);
    }
    
  • 修改medium_ai.cpp的调用逻辑:
    Column result = rust_main(&board, length);
    
  • 修改Rust端函数签名:
    pub extern "C" fn rust_main(board: &ffi::Board, length: i32) -> UniquePtr<ffi::Column> {
        // 原有逻辑不变
    }
    

2. 返回值类型不匹配

C++声明rust_main返回Column值类型,但Rust端返回UniquePtr<ffi::Column>指针类型,这种不匹配会破坏栈帧,导致参数读取异常。

解决方法:
保持两端返回值类型一致:

  • 若C++的Column是值类型,修改Rust返回值为ffi::Column:
    pub extern "C" fn rust_main(board: &ffi::Board, length: i32) -> ffi::Column {
        // ... 原有逻辑
        ffi::Column::new(rand_slot)
    }
    
  • 或修改C++端声明为指针类型,并处理内存生命周期:
    extern "C" {
    Column* rust_main(const Board* board, int length);
    }
    

3. 编译ABI一致性检查

确保C++和Rust使用相同ABI标准:

  • C++编译已启用-fPIC(CMake配置中生成共享库默认包含),无需额外调整。
  • 确认Rust编译目标平台与C++一致(如Linux下默认System V ABI,无需额外配置)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:17:06