From 631e084c7c320e895930f9ea3f30fb85de36c551 Mon Sep 17 00:00:00 2001 From: Hector PENG Date: Thu, 23 Apr 2026 09:12:15 +0800 Subject: [PATCH] Updated 'src/advanced_features/unsafe.md'. --- projects/my_rust_lib/Cargo.toml | 10 +++++ projects/my_rust_lib/main.c | 9 ++++ projects/my_rust_lib/my_app | Bin 0 -> 15888 bytes projects/my_rust_lib/src/lib.rs | 5 +++ src/advanced_features/unsafe.md | 76 +++++++++++++++++++++++++++++--- 5 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 projects/my_rust_lib/Cargo.toml create mode 100644 projects/my_rust_lib/main.c create mode 100755 projects/my_rust_lib/my_app create mode 100644 projects/my_rust_lib/src/lib.rs diff --git a/projects/my_rust_lib/Cargo.toml b/projects/my_rust_lib/Cargo.toml new file mode 100644 index 0000000..f642d7d --- /dev/null +++ b/projects/my_rust_lib/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "my_rust_lib" +version = "0.1.0" +edition = "2024" + +[lib] +name = "my_rust_lib" +crate-type = ["cdylib"] + +[dependencies] diff --git a/projects/my_rust_lib/main.c b/projects/my_rust_lib/main.c new file mode 100644 index 0000000..ed14d8f --- /dev/null +++ b/projects/my_rust_lib/main.c @@ -0,0 +1,9 @@ +#include + +extern void call_from_c(); + +int main () { + call_from_c(); + + return 0; +} diff --git a/projects/my_rust_lib/my_app b/projects/my_rust_lib/my_app new file mode 100755 index 0000000000000000000000000000000000000000..8f812de4f2d868caa841a81ed182f6501af4dca0 GIT binary patch literal 15888 zcmeHOU2Ggz6~4Q1nhmY(Z5mTIDfNI1BnWS8C$s+5=V0LmK$@c`n1jRI{zJfz~K>I)W7$)%;ZqCg6ghjZqhZ+3QA z=K&-TXs+b>?)lC+_ntX(XZDWg-Y<q2oR3 z1L_u%n_N!olNv~?OMF*7#)M~@{cO<(@oupLB0@&?+o`m3KvaNA&V&7SvqIz`J|rCg zq4)YT*qMsq9zBeSAJFf|p;WuHeRZH7FGRKcups9Ou8&zb6tY{Z5o;nqR?Kt(BHY&?aaT@-&yf%l7@rWsl)iE z^Lvo|WJrj`%>lz>TKe1R`X%MM0p+r|x!g}(@MSo4`n*d2c<{}`e|_?q!580}{%Cr< z@bcExlSlHo+5Tfk@|muDuDG<^wS2t4tN&P{QcCo?_a3)}_HG_+O*>81eKpam@%b2@ zRI7|rwUIsdYt+oV+Q)a`GsJ($v+`9;bG}e2nibnB+oq|^iJ2)glPzcGa}_&Vo|ziS zmx|dLYc`+Nx`vvxmCu`V8L~F;F-S&w87BQ)(cR$Z?;)dNuU7zGSb-mZwXzf^K z!>fX1|2fyb@3Rbtw^Qp|sVi>}rmo!Bm5RKSdS%<*PYpCn12Jb~uC-&d=Fjo14s?-P zEge0dS{wL%f~u+Y*X`!iQv)r;J8iELwV9@qd1-eO5s`~mYw=PXNi|oKxxF{$$@V<8 zvHAA4QKH?D5_<8NC0T{XI@s?6bASwuzZWIC%lnQgg!wr77X%<*4X!VH8N z2s037Ak09RfiMGM2Eq)483;4*zmNf}H^llvybo0*c*wk_k;`owyakTUB2UV?#k)kt zy2gVd<6Z24$XMUV?{8e7|MRv}V)>FRCd3-V3-Y3cwTCZ?{(WprZGr%C zQ=77$5o;o0kM~qw&&cIY4SG>E)xjqvFvMLIJ6i1N7PR+wN1qRot|@)+bc;e;lxWJlJu+`_f%wu^#o*$jB#*L-eM6*y!n_WwSj-Z+CBh zcW?KJnr)*R=b=fx;{Mqru)H1HqCtZHO!Z_AirM^fNZU^@j_;uI*4sX3L_{&sj6#sX3;D6+{6IU-7 zR0)(u?YvAj5!I%G*YCRP+p3z3`bK{1+TZEjAJD!>l}78m-%klKVC2JI;v3mdx%TZU zmh>4@^(66e)$ZjP+A(e?+N|(=0sny52iv*ewhyZs&J%xov|V9*LSr*eyHS*(8T>zI zjrcfScOwZ)jSmvPkFIZ0#*h0yD^fiv_82GddPeL|$nz1y?i<8&JVEcA1Vm07zGIla|OX$R%IMkS`>a@WNUwmlm^S zdqt?B;fXFDpKg=yrE{6ecdRk&^VW1a@AiXr+Bp8q4_KP+|%6HYquZzF;+i!@a zV9*{i@Okma^~3xG*eT5c;0O6~!2gh;HNeMUD2VF^`ukMz-~X2ltpO&r=pBRpKO>Fb zf78&WKoK=b$6)-wB98A7%=hsgg?)s<{vZQ?O}?!@f6Py>$$n7Sk%?O%1K%W;$1eKE zyb=3Jv2T>`KQ8dYIC_^j9%AsvzO?EQwpQwp2JZ-eAkQ=X{&-K@6o13>)D`#vqvY)O z$NVtXt?dyfnt`7ulQVOOAM>+z@ekT_U;ff8{foJ$f`9P-hrb^&_C05+9G3 (&mut [i32], &mut [i32]) { **清单 20-7**:从任意内存位置创建切片 -> *注*:上面的代码运行结果: +> **译注**:上面的代码运行结果: > > ```console > $ cargo run @@ -283,7 +283,7 @@ fn main() { **清单 20-8**:声明并调用在另一种语言中定义的 `extern` 函数 -> 上面代码运行结果为: +> **译注**:上面代码运行结果为: > > ```console > $ cargo run @@ -330,6 +330,70 @@ pub extern "C" fn call_from_c() { `extern` 的这种语法,仅需在属性中要求 `unsafe`,而无需在 `extern` 代码块上声明。 +> **译注**:以从 C 中调用上面的 `call_from_c` 为例,具体步骤及相应的 C 代码如下。 +> +> 1. 使用命令 `cargo new my_rust_lib --lib` 创建一个库代码箱; +> +> 2. 更新这个库代码箱的 `Cargo.toml` 文件,加入下面的内容: +> +> ```toml +> [lib] +> name = "my_rust_lib" +> crate-type = ["cdylib"] +> ``` +> +> 着一个 `lib` 小节指定了这个库代码像应被编译为一个兼容 C 的动态库。 +> +> 3. 在 `src/lib.rs` 中,使用属性 `#[unsafe(no_mangle)]` 阻止 Rust 修改函数名字,使用 `extern "C"` 来应用 C 的调用约定。 +> +> ```rust +> #[unsafe(no_mangle)] +> pub extern "C" fn call_from_c() { +> println!("刚刚从 C 调用了 Rust 函数!"); +> } +> ``` +> +> 4. 构建共享库 +> +> 运行构建命令,以生成共享对象文件(例如,Linux 上的 `.so`,MacOS 上的 `.dylib` 或 Windown 上的 `.dll`)。 +> +> ```console +> cargo build --release +> ``` +> +> 输出将位于 `target/release/libmy_rust_lib.so`(或类似的扩展名)。、 +> +> 5. 从 C 语言中调用 +> +> 为了从 C 中调用该库,咱们需要一个头文件,或一个匹配 Rust 签名的函数原型。 +> +> ```c +> #include +> +> extern void call_from_c(); +> +> int main () { +> call_from_c(); +> +> return 0; +> } +> ``` +> +> 6. 编译和链接 +> +> 在编译 C 代码时,要将其与生成的 Rust 库链接。咱们可需需要设置 `LD_LIBRARY_PATH`(在 Linux 上),以便系统可以在运行时找到该共享对象。 +> +> ```bash +> # 编译并链接(根据需要调整路径和库名) +> $ gcc main.c -L./target/release -lmy_rust_lib -o my_app +> +> # 运行程序 +> $ export LD_LIBRARY_PATH=./target/release:$LD_LIBRARY_PATH +> $ ./my_app +> 刚刚从 C 调用了 Rust 函数! +> ``` +> +> 专业提示:对于复杂的项目,请使用 [`cbindgen`](https://github.com/mozilla/cbindgen) 工具,从咱们的 Rust 代码自动生成 C/C++ 头文件。 ## 访问或修改可变静态变量 @@ -360,7 +424,7 @@ fn main() { ```rust static mut COUNTER: u32 = 0; -/// 安全提示:同时从多个线程调用此函数属于未定义行为, +/// SAFETY:同时从多个线程调用此函数属于未定义行为, /// 因此咱们 *必须* 确保每次仅从单个线程调用他。 fn add_to_count(inc: u32) { @@ -371,7 +435,7 @@ fn add_to_count(inc: u32) { fn main() { unsafe { - // 安全提示:此函数仅在 `main` 中的单个线程中调用。 + // SAFETY:此函数仅在 `main` 中的单个线程中调用。 add_to_count(3); println! ("COUNTER: {}", *(&raw const COUNTER)); } @@ -382,7 +446,7 @@ fn main() { 与常规变量一样,我们使用 `mut` 关键字指定可变性。任何读写 `COUNTER` 的代码都必须位于 `unsafe` 代码块内。清单 20-11 中的代码会编译并如预期打印 `COUNT: 3` ,因为他是单线程的。让多个线程访问 `COUNTER` 可能会导致数据竞争,因此这属于为定义行为。因此,我们需要标记整个函数为 `unsafe` 并记录安全限制,以便任何调用该函数的人,都知道哪些是可以安全执行,哪些不可以安全执行。 -每当我们编写不安全的函数时,惯例是在代码中添加以 `SAFETY` 开头的注释,并解释调用者需要采取哪些措施才能安全地调用该函数。同样,每当我们执行不安全的操作时,惯例也是添加以 `SAFETY` 开头的注释,说明安全规则是如何得到维护的。 +每当我们编写不安全的函数时,惯例是在代码中添加以 `SAFETY`(安全提示) 开头的注释,并解释调用者需要采取哪些措施才能安全地调用该函数。同样,每当我们执行不安全的操作时,惯例也是添加以 `SAFETY` 开头的注释,说明安全规则是如何得到维护的。 此外,编译器会默认通过编译器 lint 规则阻止任何试图创建可变静态变量引用操作。您必须通过添加 #[allow(static_mut_refs)] 注解来显式禁用该 lint 规则的保护,或者通过使用原始借用运算符之一创建的原始指针来访问该可变静态变量。 这包括隐式创建引用的情况,例如本代码片段中在 `println!` 中的用法。要求通过原始指针创建对静态可变变量的引用,有助于使使用它们的安全要求更加明确。