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
- You're ignoring the
ResultfromCString::new:CString::newreturns aResult<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. - The pointer address handling is technically risky (and possibly incorrect if you didn't unwrap the Result):
Ifstris still aResult(not an unwrappedCString), callingas_ptr()on it won't work at all. Even if you did unwrap it, while&str.as_ptr() as *const *const c_charcompiles, 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

