当前位置: 首页 > article >正文

Rust: CString、CStr和String、str

在FFI与C交互中,少不了与C中字符串交互。在Rust中,有

各种String存在的意义:
OsString:因为要与操作系统等复杂的世界交互;
因为Rust世界中的Strings 始终是有效的 UTF-8。对于非 UTF-8 字符串,可以用到OsString。
CString: 与C的世界进行交互;
String:在Rust的世界中交互;

一、CString、String等代码探析

因为有用到外部libc库,所以:

1、toml文件


[dependencies]
libc = "0.2"

2、相关代码

use std::ffi::{CStr, CString,c_char};
use std::borrow::Cow;
fn main() {println!("Hello, world!");show_cstring_bytes(CString::new("Hello, world!").expect("CString::new failed"));show_string_bytes("Hello, world!".to_string());}// as:不consume
// from/into:consume ownship
// into_bytes(),as_bytes()返回的缓冲区不包含尾随 nul 终止符,并且保证不包含任何内部 nul 字节。
// 必须用as_bytes_with_nul()返回的缓冲区包含 nul 终止符。
fn show_cstring_bytes_no_null(s:CString){let c_string_bytes = s.as_bytes();println!("c_string_bytes no null   : {:?}  len: {:?}", c_string_bytes,c_string_bytes.len());
}
fn show_cstring_bytes(s:CString){let c_string_bytes = s.as_bytes_with_nul();println!("c_string_bytes with null : {:?}  len: {:?}", c_string_bytes,c_string_bytes.len());}
fn show_string_bytes(s:String){let string_bytes = s.into_bytes();println!("  string_bytes           : {:?} len :{:?}", string_bytes,string_bytes.len());
}
// CString ->&CStr
fn cstring_to_cstr(s:&CString) ->&CStr{s.as_c_str()}
fn show_cstr_bytes_no_null(s:&CStr){let c_str_bytes = s.to_bytes();println!("c_str_bytes   no null: {:?}  len: {:?}", c_str_bytes,c_str_bytes.len());
}
fn show_cstr_bytes_with_null(s:&CStr){let c_str_bytes = s.to_bytes_with_nul();println!("c_str_bytes with null: {:?}  len: {:?}", c_str_bytes,c_str_bytes.len());
}
fn cstring_to_str(s:&CString) ->&str{s.to_str().expect("CString to str failed")
}
fn cstr_to_cstring(s:&CStr) ->CString{s.to_owned()
}
// *const c_char具体是*const i8 还是 *const u8由平台决定。
fn get_ptr_c_char() ->*const c_char{const BYTES: &[u8] = b"Hello, world! to c_char!\0";//或是:BYTES.as_ptr().cast()BYTES.as_ptr() as *const _ 
}fn get_cstr_from_bytes<'a>() ->&'a CStr{const BYTES_: &[u8] = b"Hello, world! from bytes!\0";let cstr = CStr::from_bytes_with_nul(BYTES_).expect("CStr::from_bytes_with_nul failed");cstr
}
fn get_cstr_from_ptr_c_char<'a>(s:*const c_char) ->&'a CStr{unsafe { CStr::from_ptr(s) }
}fn get_cstring() ->CString{let c_string = CString::new("Hello, world! from c string!").expect("CString::new failed");c_string}
fn check_cstring(s: *const c_char) -> bool{unsafe {let slice = CStr::from_ptr(s);let my_str = slice.to_str();match my_str{Ok(_) => return true,Err(_) => return false,};//println!("my_str: {}", my_str.expect("CStr::from_ptr failed"));}}fn cstr_to_str(s:&CStr) ->&str{s.to_str().expect("CStr::from_ptr failed")
}
fn cstring_to_cow_str(s:&CString) ->Cow<'_,str>{//let c_string = CString::new("Hello, world! from c string!").expect("CString::new failed");let c_string_ptr = s.as_ptr();let cow = unsafe { CStr::from_ptr(c_string_ptr).to_string_lossy() }; // COW<'_,str>cow
}
fn cstr_to_cow_str(s:&CStr) ->Cow<'_,str>{s.to_string_lossy()
}fn cstring_to_box_cstr(s:CString) ->Box<CStr>{s.into_boxed_c_str()
}
fn box_cstr_to_cstring(s:Box<CStr>) ->CString{s.into_c_string()
}fn vec_u8_with_null_to_cstring_unchecked(v:Vec<u8>) ->CString{unsafe{CString::from_vec_with_nul_unchecked(v)}
}
fn vec_u8_with_null_to_cstring_checked(v:Vec<u8>) ->CString{CString::from_vec_with_nul(v).expect("CString::from_vec_with_nul failed")
}fn vec_u8_no_null_to_cstring(v:Vec<u8>) ->CString{unsafe{CString::from_vec_unchecked(v)}
}
fn bytes_with_null_to_cstr_unchecked(bytes:&[u8]) ->&CStr{unsafe{ CStr::from_bytes_with_nul_unchecked(bytes) }
}
fn bytes_with_null_to_cstr_check(bytes:&[u8]) ->&CStr{unsafe{ CStr::from_bytes_with_nul(bytes).unwrap() }
}
fn bytes_no_null_to_cstr(bytes:&[u8]) ->&CStr{unsafe{ CStr::from_bytes_until_nul(bytes).unwrap() }
}
// MUST *mut : move ownership
fn ptr_to_cstring(ptr:*mut c_char) ->CString{unsafe{ CString::from_raw(ptr) }
}
// MUST:*mut : consume ownership
fn cstring_to_ptr_with_consume(s:CString) ->*mut c_char{s.into_raw() // s 被消耗,不能再使用
}
fn cstring_to_ptr_no_consume(s:&CString) ->*const c_char{s.as_ptr()
}
fn ptr_to_cstr<'a>(ptr: *const i8) ->&'a CStr{unsafe{ CStr::from_ptr(ptr) }
}
fn cstring_to_string(s:CString) ->String{// let c_string_ptr = s.as_ptr();// let my_string = unsafe { CStr::from_ptr(c_string_ptr).to_string_lossy() }; // COW<'_,str>// println!("my_string: {}", my_string);s.into_string().unwrap() // 消耗s,不能再使用}
fn string_to_cstring(s: String) ->CString{let c_string = CString::new(&*s).expect("CString::new failed");c_string
}
//C中分配内存,C中释放内存
fn c_allocate_for_rust_as_cstring(){#[allow(unused_extern_crates)]extern crate libc; //toml文件中,需要添加libc = "0.2"// 分配内存来存储一个字符串let size = 12; // 例如,分配足够存储 "Hello, world" 的内存let ptr = unsafe { libc::malloc(size) as *mut c_char };if !ptr.is_null() {// 使用 C 字符串格式填充内存let c_str = CString::new("Hello, world").unwrap();unsafe{std::ptr::copy_nonoverlapping(c_str.as_ptr(), ptr, size);}// 使用 CStr 来安全地访问这个内存let rust_str = unsafe { CStr::from_ptr(ptr) };println!("{}", rust_str.to_str().unwrap());unsafe{// 释放内存libc::free(ptr as *mut _);}} else {println!("Memory allocation failed");}
}

二、输出结果

Hello, world!
c_string_bytes with null : [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33, 0]  len: 14string_bytes           : [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] len :13  

可以看到,在CString和String转化为字节后的本质区别。

相关的转化具体见上面的代码,有助于加深认识。

http://www.lryc.cn/news/2397409.html

相关文章:

  • 力扣每日一题——连接两棵树后最大目标节点数目 ||
  • 【学习笔记】Sparse Crosscoders for Cross-Layer Features and Model Diffing
  • VSCode无法转到定义python源码(ctrl加单击不跳转)
  • 【华为战报】4月、5月 HCIP考试战报!
  • 开发指南120-表格(el-table)斑马纹
  • 数字化转型全场景安全解析:从产品到管理的防线构建与实施要点
  • AIGC工具平台-GPT-SoVITS-v4-TTS音频推理克隆
  • el-table配置表头固定而且高度变化
  • 设计模式——组合设计模式(结构型)
  • PostgreSQL 在生物信息学中的应用
  • EMO2:基于末端执行器引导的音频驱动虚拟形象视频生成
  • 计算机总线技术深度解析:从系统架构到前沿演进
  • Python打卡训练营Day43
  • PHP7+MySQL5.6 查立得轻量级公交查询系统
  • 如何做好一个决策:基于 Excel的决策树+敏感性分析应用(针对多个变量)
  • Azure DevOps 管道部署系列之一本地服务器
  • DeepSeekMath:突破开放式语言模型中数学推理能力的极限
  • QT 5.15.2 程序中文乱码
  • Celery简介
  • StarRocks物化视图
  • vue2源码解析——响应式原理
  • 基于 GitLab CI + Inno Setup 实现 Windows 程序自动化打包发布方案
  • 做好 4个基本动作,拦住性能优化改坏原功能的bug
  • 【HarmonyOS 5】针对 Harmony-Cordova 性能优化,涵盖原生插件开发、线程管理和资源加载等关键场景
  • 零基础认知企业级数据分析平台如何落实数据建模(GAI)
  • web架构2------(nginx多站点配置,include配置文件,日志,basic认证,ssl认证)
  • AI 的早期萌芽?用 Swift 演绎约翰·康威的「生命游戏」
  • 【DBA】MySQL经典250题,改自OCP英文题库中文版(2025完整版)
  • Cursor 编辑器介绍:专为程序员打造的 AI 编程 IDE
  • go|channel源码分析