CString::new().unwrap().as_ptr()返回空的*const c_char。

3

我有一个期望接受 *const std::os::raw::c_char 的C函数,而我在Rust中已经这样做了:

use std::os::raw::c_char;
use std::ffi::{CString, CStr};
extern crate libc;

fn main() {
    let _test_str: *const c_char = CString::new("Hello World").unwrap().as_ptr();
    let fmt: *const c_char = CString::new("%s\n").unwrap().as_ptr();
    unsafe { libc::printf(fmt, _test_str); }

    unsafe {
        let slice = CStr::from_ptr(_test_str);
        println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
    }
}

然而,我无法使_test_str打印出来,上述程序的输出仅为:
string buffer size without nul terminator: 0

如果我将_test_str传递给某个C函数,发现它是一个空字符串,那么我做错了什么?

1
@trentcl 没想到如果我一直盯着页面的介绍部分而不是 as_ptr 函数的子部分说明会看到警告。我的错,但是“鲁莽”太过了。无论如何感谢你指出参考资料。此外,你指出的问题更为冗长,难以抓住关键点。 - xxks-kkk
1
很抱歉我没有直接链接到相关部分,但我根本不应该链接;你有责任保证你编写的任何unsafe代码,并包括在解引用它们之前阅读返回原始指针的函数的文档。至于重复问题,我同意,那个问题有点冗长。实际上,如何在使用as_ptr()时停止内存泄漏?可能更好。然而,我只有一个关闭投票,所以现在无法更改。 - trent
1个回答

8

您在同一语句中创建了一个指向CString的指针。该CString是有主人但没有绑定到变量,因此它只能存在于封闭语句的生命周期内,导致指针无效。这是由 as_ptr 文档明确警告的:

For example, the following code will cause undefined behavior when ptr is used inside the unsafe block:

use std::ffi::{CString};

let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
unsafe {
    // `ptr` is dangling
    *ptr;
}

This happens because the pointer returned by as_ptr does not carry any lifetime information and the CString is deallocated immediately after the CString::new("Hello").expect("CString::new failed").as_ptr() expression is evaluated.

您可以通过引入整个函数都存在的变量,并创建指向这些变量的指针来解决该问题:
fn main() {
    let owned_test = CString::new("Hello World").unwrap();
    let _test_str: *const c_char = owned_test.as_ptr();
    let owned_fmt = CString::new("%s\n").unwrap();
    let fmt: *const c_char = owned_fmt.as_ptr();

    unsafe {
        libc::printf(fmt, _test_str);
    }

    unsafe {
        let slice = CStr::from_ptr(_test_str);
        println!(
            "string buffer size without nul terminator: {}",
            slice.to_bytes().len()
        );
    }

    // owned_fmt is dropped here, making fmt invalid
    // owned_test is dropped here, making _test_str invalid
}

如果您正在使用原始指针,需要特别小心确保它们始终指向有效数据。引入变量是控制数据生存时间的最佳方式 - 它将从变量初始化到变量超出作用域的时刻存活。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接