明明Rust可以直接调用C了,为什么还设计出了unsafe模式_-Ivony
你这个想法和Java当年如出一辙,二十年的教训除了Javaer没几个人能视而不见。
首先就是跨语言调用天然就是有损耗的,两种语言的代码要分别编译,很多优化就没法做了。比如说循环访问数组元素,并不需要每次都检查是否越界,因为编译器可以轻松地发现有对应的约束确保不会越界,这就可以优化掉。再比如说内联、循环展开、尾递归……
其次就是FFI对于语法来说几乎只能包装成函数调用。但是本质上来讲一切运算符都可以改写为函数调用,但那种代码你愿意写吗?
Add( a, b ),这么写代码和写汇编啥区别?
最后就是C#其实证明了一件事情,引入unsafe通常情况下并不会被滥用。因为绝大多数程序员根本不会用,你只需要将safe写法的语法优化成一等公民的地位,大家自然会选择safe的语法。C++的问题其实就在于从语法上来看,unsafe的写法反而更简洁,所以你防不住那些程序员裸指针满天飞……
====================================================
最后再补充一点儿私货,姑妄听之。
从我观察来看,C#搞了unsafe后还有一个好处就是后续可以把一些unsafe的pattern抽出来做一些safe的封装,所以unsafe反而会使得unsafe的东西变少。但是如果你特么习惯了unsafe的直接丢给native去搞,那么这些pattern就变成了native library。
举个栗子:最开始C#在栈上分配内存必须是unsafe的。这很好理解,栈内存分配结果必然是个指针,引用类型的引用不能搞到栈上,因为有指针只能是unsafe的。
结果现在可以直接用Span
虽然我目前用不到这些场景,但是想想Span
评论区
云破月来: "你只需要将safe写法的语法优化成一等公民的地位,大家自然会选择safe的语法"一针见血的 👍🏽46 💭上海 🕐2024-04-08 01:13:56
│ └── Supernova: 对的,当年看C++也有推荐加const之类的,说更能避免出错,但是写着写着就懒了 👍🏽6 💭天津 🕐2024-04-08 16:33:10
│ └── Ivony: 现在的趋势是变量是可变的要额外声明,否则就认为是只读的,也是这个原因。你要多写个readonly,程序员就犯懒…… 👍🏽28 💭广东 🕐2024-04-10 10:41:23
│ └── 梦说人痴: ts的const要比let多打两个字母也不是个设计[赞同] 👍🏽1 💭广东 🕐2024-08-02 03:29:45
萧叶轩: 很多人意识不到调用C函数也是跨语言调用,对C++和Rust来说字符串是重灾区,对其他gc语言来说是数组 👍🏽39 💭辽宁 🕐2024-04-03 10:38:26
│ └── Dnomd343: c++没影响的,字符串可以直接内存引用,反过来也有string_view这种东西。 👍🏽5 💭广东 🕐2024-04-03 19:26:02
│ └── 萧叶轩: 问题是生存期,不是能不能读。 👍🏽13 💭辽宁 🕐2024-04-03 21:53:18
│ └── 我变成了一条鱼: 主要调c麻烦,字符串还得转cstr引入一次拷贝 👍🏽0 💭广东 🕐2024-04-05 19:53:38
吓死隔壁老王了: [赞][赞][赞]c#的unsafe一般用不上,是给高手准备的。不管啥语言,指针向菜鸡开放并使用,那很容易变灾难 👍🏽29 💭重庆 🕐2024-04-03 12:20:15
│ └── 南屏晚风: C#的unsafe已经足够警告菜鸟了,并且默认禁用unsafe语句,没两把刷子还是用常规写法比较好,除非你很明确自己的需求 👍🏽3 💭安徽 🕐2024-04-03 15:15:08
│ └── SongHasNoName: 对bitmap操作有性能需求时会用到unsafe 👍🏽0 💭河南 🕐2024-04-03 16:05:09
│ └── Ivony: 现在通过Memory<T>可以很大程度上不需要unsafe了…… 👍🏽8 💭广东 🕐2024-04-03 16:06:27
│ └── 更深的蓝: 结合 Span<T>、Memory<T>、原生struct还有 stackalloc 等特性,除非写类似图像处理这样的库,不然完全不需要“unsafe”这东西 👍🏽5 💭广东 🕐2024-04-04 14:53:55
│ └── 呓语: 高效的序列化反序列化还是需要的,用指针叉出来比任何方式都高效紧凑 👍🏽2 💭上海 🕐2024-04-04 23:20:13
│ └── 霍姚远: 序列化要啥指针啊,Span随便就搞定了目前标准库里都只有数字ToString和TensorPrimitives在主用指针了 👍🏽5 💭江苏 🕐2024-04-06 20:36:35
温水煮华雄: C艹unsafe写法更简洁真的绷不住了[飙泪笑] 👍🏽17 💭湖北 🕐2024-04-04 15:48:23
DearFuture: 把危险的做法弄得难用就解决了[飙泪笑] 👍🏽13 💭广东 🕐2024-09-06 01:09:53
│ └── 黎明: 约束本身是会让东西更复杂,看工程项目怎么选了 👍🏽2 💭四川 🕐2024-10-04 20:57:44
│ └── 剔刀: 把危险的做法本事的复杂性和危险性暴露给你就叫做难用?[飙泪笑] 👍🏽0 💭法国 🕐2025-06-26 05:23:10
Erinacio: [思考]C/C++ 代码用 clang 编译,能否和同样用 llvm 的 Rust 实现跨语言 LTO 呢 👍🏽7 💭新加坡 🕐2024-04-03 15:50:09
│ └── Ivony: 没研究,理论上有可行性……[滑稽] 👍🏽0 💭广东 🕐2024-04-03 15:52:02
│ └── 节能的鼹鼠: 可以的,https://www.zhihu.com/question/54029017/answer/137952875?utm_psn=1758924771629453312 👍🏽5 💭北京 🕐2024-04-03 18:33:21
│ └── Dnomd343: 可以的,现在就可以做到 👍🏽0 💭广东 🕐2024-04-03 19:24:28
│ └── AlseinX: 可以lto,但是经过c-abi会丢失泛型,丢失泛型也就意味着失去零开销抽象的静态分发能力,性能有损是无法避免的。最重要的一点是,经过ffi最大的问题并不是性能问题,而是代码复杂度,开发和维护成本的问题。 👍🏽8 💭上海 🕐2024-04-04 04:27:27
│ └── 朝花夕拾: rust的泛型是语法上的泛型,编译时实际上进行的泛型实际化。 👍🏽0 💭四川 🕐2024-06-30 11:54:49
│ └── AlseinX: 嗯,所以呢? 👍🏽0 💭上海 🕐2024-06-30 14:41:44
史莱姆捏: 啊,不是。静态链接开lto,rust调c真没啥损耗。 👍🏽1 💭江苏 🕐2024-10-11 16:50:09
小筑: Java 日常被拷打[开心]大佬有没有什么 java native 历史坑点的相关文章分享一下 👍🏽2 💭山东 🕐2024-04-04 00:47:34
│ └── BobH-Official: 不知道,但是我知道他们自己放弃了 unsafe[doge] 👍🏽1 💭新加坡 🕐2024-10-05 14:52:45
原野: 确实,c++要写安全的代码就肯定和简洁沾不上边了 👍🏽0 💭广东 🕐2025-05-21 12:28:44
无妄: add (a, b) 去掉括号和逗号不就是前缀表达式了吗,挺好的,愿意写 👍🏽0 💭江苏 🕐2024-10-25 12:23:53
我就送你一个字寄: 因为rust设计是安全需要rust认为c不一定安全所以要跟编译器讲一下 👍🏽0 💭中国香港 🕐2024-10-18 18:00:03
│ └── what72e: 没理解题意,和我刚进来前一样 👍🏽1 💭吉林 🕐2024-12-25 01:45:58
Karmylr: C内联汇编算不算跨语言调用?也会有损耗吗 👍🏽0 💭福建 🕐2024-04-14 22:49:04
└── Ivony: 一般不认为跨语言了,因为这里面没有边界…… <span class="small-blue">👍🏽5 💭广东 🕐2024-04-20 02:11:26</span>
└── McEndu: 个人认为也算,把中间量用的寄存器定死(x86的rax、xmm0之类的)会影响编译器的寄存器分配策略 <span class="small-blue">👍🏽0 💭北京 🕐2025-05-03 12:28:28</span>