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

Rust中CString转*const *const c_char的FFI调用问题咨询

Hey there! Let's break down your issue step by step, fix the conversion, and talk about how to verify it works correctly.

First, let's spot the issues in your current code

  1. You're ignoring the Result from CString::new:
    CString::new returns a Result<CString, NulError> because it will fail if your input string contains any null bytes (\0). Skipping error handling here can lead to silent panics or undefined behavior later.
  2. The pointer address handling is technically risky (and possibly incorrect if you didn't unwrap the Result):
    If str is still a Result (not an unwrapped CString), calling as_ptr() on it won't work at all. Even if you did unwrap it, while &str.as_ptr() as *const *const c_char compiles, it's cleaner (and easier to verify) to explicitly capture the pointer first.

Here's the correct way to convert and call foo

Let's rewrite your code with proper error handling and safe pointer management:

use std::ffi::{CString, c_char};
use std::fs;

// Declare the external C function (make sure this matches the C signature exactly)
extern "C" {
    fn foo(strings: *const *const c_char, num_of_strings: i32);
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Read the file content and handle any IO errors
    let file_content = fs::read_to_string("path/to/file")?;
    
    // Convert to CString (fails if content has null bytes)
    let c_string = CString::new(file_content.clone())?;
    
    // Get the raw pointer to the C string
    let c_str_ptr = c_string.as_ptr();
    
    // Call the C function: pass the address of our pointer (matches C's `&str`)
    unsafe {
        foo(&c_str_ptr as *const *const c_char, 1);
    }

    Ok(())
}

How to verify your conversion is correct

There are two straightforward ways to confirm everything is working as expected:

1. Add debug prints in both Rust and C

In your C foo function, add prints to check the pointer addresses and string content:

#include <stdio.h>

void foo(const char** strings, int num_of_strings) {
    for (int i = 0; i < num_of_strings; i++) {
        printf("Received pointer array element %d: %p\n", i, strings[i]);
        printf("String content: %s\n", strings[i]);
    }
}

In Rust, print the pointer values before calling foo:

// Add this right before the unsafe block
println!("CString pointer: {:p}", c_str_ptr);
println!("Pointer to pointer: {:p}", &c_str_ptr as *const *const c_char);

Compare the addresses: the Received pointer array element 0 should match the CString pointer from Rust, and the pointer-to-pointer value should match what foo sees as the strings argument.

2. Validate the pointer directly in Rust

You can dereference the double pointer in Rust (unsafely) and convert it back to a Rust string to confirm it matches the original content:

unsafe {
    // Dereference the double pointer to get the original C string pointer
    let retrieved_ptr = *(&c_str_ptr as *const *const c_char);
    // Convert back to a CStr to safely read the string
    let retrieved_cstr = std::ffi::CStr::from_ptr(retrieved_ptr);
    // Check if it matches our original file content
    assert_eq!(retrieved_cstr.to_str()?, file_content);
    println!("Conversion verified: strings match!");
}

Resources to deepen your FFI knowledge

  • Rust Official FFI Guide: Covers all the basics of interacting with C from Rust, including string handling, pointer safety, and foreign function declarations.
  • The Rustonomicon (FFI Section): Dives into the unsafe guarantees you need to uphold when working with C code, including lifetime management and pointer validity.
  • Rust Cookbook - FFI Recipes: Has practical, ready-to-use examples for common FFI tasks like passing strings, arrays, and structs between Rust and C.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:21:44