如何将C字符串转换为Rust字符串并通过FFI返回?

我正在尝试获取C库返回的C字符串,并通过FFI将其转换为Rust字符串。

mylib.c

const char* hello(){return "Hello World!";
}main.rs#![feature(link_args)]extern crate libc;
use libc::c_char;#[link_args = "-L . -I . -lmylib"]
extern {fn hello() -> *c_char;
}fn main() {//how do I get a str representation of hello() here?
}

解决方案:

在Rust中使用C字符串的最佳方法是使用CString::from_raw模块中的结构,即CString::from_raw和CString::from_raw。

CString::from_raw是动态大小的类型,因此只能通过指针使用。 这使其与常规malloc类型非常相似。 您可以使用不安全的CString::from_raw静态方法从&str构造free。 此方法是不安全的,因为不能保证传递给它的原始指针有效,它确实指向有效的C字符串,并且该字符串的生存期是正确的。

您可以使用malloc的CString::from_raw方法获得CString::from_raw。

这是一个例子:

extern crate libc;use libc::c_char;
use std::ffi::CStr;
use std::str;extern {fn hello() -> *const c_char;
}fn main() {let c_buf: *const c_char = unsafe { hello() };let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };let str_slice: &str = c_str.to_str().unwrap();let str_buf: String = str_slice.to_owned();  // if necessary
}

您需要考虑CString::from_raw指针的寿命以及谁拥有它们。 根据C API,您可能需要在字符串上调用特殊的释放函数。 您需要仔细安排转换,以使切片不会超过指针的寿命。 malloc返回具有任意生存期的free的事实在这里有帮助(尽管它本身很危险); 例如,您可以将C字符串封装到一个结构中,并提供&str转换,以便您可以像使用字符串切片一样使用该结构:

extern crate libc;use libc::c_char;
use std::ops::Deref;
use std::ffi::CStr;extern "C" {fn hello() -> *const c_char;fn goodbye(s: *const c_char);
}struct Greeting {message: *const c_char,
}impl Drop for Greeting {fn drop(&mut self) {unsafe {goodbye(self.message);}}
}impl Greeting {fn new() -> Greeting {Greeting { message: unsafe { hello() } }}
}impl Deref for Greeting {type Target = str;fn deref<'a>(&'a self) -> &'a str {let c_str = unsafe { CStr::from_ptr(self.message) };c_str.to_str().unwrap()}
}

此模块中还有另一种类型,称为CString::from_raw。它与CString::from_raw具有malloc,其中free具有相同的关系-&str是Vec< u8 >的拥有版本。这意味着它“持有”字节数据分配的句柄,并丢弃该句柄 &[u8]会释放它提供的内存(实际上,Vec< u8>包装String,而后者将被丢弃)。 因此,当您希望将Rust中分配的数据公开为C字符串时,这很有用。

不幸的是,C字符串总是以零字节结尾,并且不能在其中包含一个,而Rust CString::from_raw/malloc恰好相反-它们不以零字节结尾,并且可以在其中包含任意数量的字符串。 这意味着从free到&str既没有错误也没有分配-Vec< u8 >构造函数都检查您提供的数据内部是否为零,如果发现错误则返回错误,并将零字节附加到字节的末尾 向量可能需要重新分配。

就像实现malloc的CString::from_raw,实现&str的free一样,您可以直接在&[u8]上调用在Vec< u8 >上定义的方法。这很重要,因为CString::from_raw方法返回了2950000612479599599622的调用,而2950000612479599599是直接在C上进行互操作所必需的。 CString值,这很方便。

可以从可以转换为malloc的所有内容中创建CString::from_raw。free、&str、Vec< u8 >和&[u8]是构造函数&[u8]的有效参数。自然地,如果您传递字节片或字符串片,则会创建新的分配, 而Vec< u8 >或String将被消耗。

extern crate libc;use libc::c_char;
use std::ffi::CString;fn main() {let c_str_1 = CString::new("hello").unwrap(); // from a &str, creates a new allocationlet c_str_2 = CString::new(b"world" as &[u8]).unwrap(); // from a &[u8], creates a new allocationlet data: Vec<u8> = b"12345678".to_vec(); // from a Vec<u8>, consumes itlet c_str_3 = CString::new(data).unwrap();// and now you can obtain a pointer to a valid zero-terminated string// make sure you don't use it after c_str_2 is droppedlet c_ptr: *const c_char = c_str_2.as_ptr();// the following will print an error message because the source data// contains zero byteslet data: Vec<u8> = vec![1, 2, 3, 0, 4, 5, 0, 6];match CString::new(data) {Ok(c_str_4) => println!("Got a C string: {:p}", c_str_4.as_ptr()),Err(e) => println!("Error getting a C string: {}", e),}
}

如果您需要将CString::from_raw的所有权转让给C代码,则可以调用CString::from_raw。然后,您需要取回指针并在Rust中释放它; Rust分配器不太可能与malloc和free使用的分配器相同。您所需要做的只是调用CString::from_raw,然后允许正常删除字符串。

Rust : 如何将C字符串转换为Rust字符串并通过FFI返回?相关推荐

  1. mysql update分割字符串_mysql 截取字符串并 update select

    亲测有效  格式为 update 需要修改的表 b1 inner join (查询到的临时表)b2 on b1.id=b2.id set b1.要修改的字段=b2.查询到的值 因为想要把表中的一个字段 ...

  2. SAP-ABAP 内表数据转换为十六进制字符串并利用服务器转储

    函数:SOTR_SERV_TABLE_TO_STRING SCMS_STRING_TO_XSTRING 类 IF_HTTP_RESPONSE 内表数据转换为16进制存储需要先把表体内容转换成一定的格式 ...

  3. Python字符串转换为小写字母– str.lower()

    We can convert a string to lowercase in Python using str.lower() function. In this short tutorial, w ...

  4. js获取字符串最后一个字符代码

    方法一:运用String对象下的charAt方法 charAt() 方法可返回指定位置的字符. 代码如下 复制代码 str.charAt(str.length – 1) 请注意,JavaScript ...

  5. 字符串分割(split),将字符串按照指定字符进行分割。split(String regex)和split(String regex, int limit)

    一.split(String regex)字符串分割,将字符串按照指定字符进行分割,返回的是一个字符串数组. public String[] split(String regex) {return s ...

  6. Rust语言教程(4) - 字符串

    Rust语言教程(4) - 字符串 有了数组和向量的基础,我们再来看它的一个特例:字符串. 字符串有两种表现形式,一种是基本类型,表示字符串的切片,以&str表示:另一种是可变的string类 ...

  7. Java 将字符串转换为字符数组 toCharArray()

    Java 手册 toCharArray public char[] toCharArray() 将此字符串转换为一个新的字符数组. 返回: 一个新分配的字符数组,它的长度是此字符串的长度,它的内容被初 ...

  8. mysql 字符转数组_mysql下将分隔字符串转换为数组

    MySQL存储过程可以用于分割字符串,下面就为您详细介绍这种MySQL存储过程的用法,供您参考学习之用. 现有一段字符串,如apple,banana,orange,pears,grape,要把它按照逗 ...

  9. python字节流转化为字符串报错_python3.x,_关于Python3字符串转换为字节流的问题,python3.x - phpStudy...

    关于Python3字符串转换为字节流的问题 un = 'BZh91AY&SYA\xaf\x82\r\x00\x00\x01\x01\x80\x02\xc0\x02\x00 \x00!\x9ah ...

  10. 输入一个以回车结束的字符串(少于80个字符),滤去所有的非十六进制字符后,组成一个新字符串(十六进制形式),输出该字符串并将其转换为十进制数后输出。

    [问题描述] 输入一个以回车结束的字符串(少于80个字符),滤去所有的非十六进制字符后,组成一个新字符串(十六进制形式),输出该字符串并将其转换为十进制数后输出. [输入形式]一个字符串,小于80个字 ...

最新文章

  1. Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(andro
  2. CHKDSK解决文件损坏无法打开E盘
  3. 利用泛型和反射,将从数据库select出来的集合直接转换成对象
  4. 将Quartz与Spring集成
  5. 使用Spring-Cloud将Spring Boot应用程序部署到Cloud Foundry
  6. where 泛型类型约束 default 关键字
  7. 吴军:为什么计算机不是万能的
  8. Spring mvc 拦截器 配置心得
  9. 深入理解 Tomcat(四)Tomcat 类加载器之为何违背双亲委派模型
  10. 单例模式及多线程安全(C++版)
  11. 读书笔记:陈希孺:概率论与数理统计:2014.01.01
  12. Vue3+ts+vite 国际化处理
  13. 保险中介系列法规年内出台
  14. UMD算法讲义——Lecture 3:算法设计回顾:数学背景
  15. w ndows7旗舰版怎么重装系统,windows7旗舰版64位重装系统图文教程
  16. CSS之background深度详解
  17. win7系统定时删除数据的批处理命令_win7如何一键清理系统垃圾|win7批处理命令清理垃圾的方法...
  18. 一个有趣公众号的简介-网络灯下黑
  19. springboot中 @Imput与@EnableConfigurationProperties区别
  20. 小米8 twrp recovery_小米手机机型怎么刷入脸谱Magisk模块详细教程

热门文章

  1. 数据结构-阶段性理解
  2. Cron定时任务应用到Thinkphp – 贤生博客
  3. 第一节:setTimeout和setInterval定时器
  4. 20165234 《Java程序设计》第八周学习总结
  5. 移动端 短信发送,一键拨号功能
  6. snprintf/strncpy/strlcpy速度测试
  7. Java:for循环出现for(int i : arr)
  8. python语句和语法结构
  9. unity相机的两种不模式的区别
  10. Atitit  Persistence API持久性标准化法总结 目录 1. 持久性对于大多数企业应用程序都非常要害 1 2. 持久化api内容 2 2.1. 一种声明式地执行O-R映射的方式。 2