2312d,d语言来绑定C++和rust

原文

各编译语言相同概念

1,按可重用函数拆分代码.
2,由源码中的函数名生成的串来标识函数.如,g++void foo()生成_Z3foov的标识.此串总是是可重现的;如,Linux上的ClangGCC都遵循ItaniumC++ABI约定来装饰函数名.

3,在内存中的特定位置存储该函数的所有参数,然后用调用等效指令把控制权移动到函数来调用函数.
如,要调用前面的void foo(),编译器会转换C++foo();语句为汇编调用(call) _Z3foov.然后,汇编用适当的操作码替换调用,并用_Z3foov标识的第一条指令位置替换_Z3foov.

4,(如果有)在特定位置存储函数返回值,然后使用ret指令或等效指令返回.
5,类和结构可当作原语类型集合(尽管有些类确实有虚表).
6,类方法只是另一个类对象指针为第一个参数的函数.即,这样写时:

class Foo
{void foo(int bar);int baz;
};

翻译为:

class Foo
{int baz;
};
void foo(Foo *this, int bar);

既然每种编译语言都用相同概念编译,为什么它们不能交互呢?
我想举一例来说明要实现的目标:

//文件:`main.cpp`
#include "rustmodule.h"
//或在理想的`C++20`世界中:
//import rustmodule;
int main()
{foo();return 0;
}
//-----------
//文件:`rustmodule.h`
#pragma once
//这是在`Rust`中定义的
void foo();
//-----------
//文件:`rustmodule.rs`
pub fn foo() {println!("Hello from Rust");
}

想可编译这些文件,并得到一个从Rust打印Hellostdout的可执行文件.

现在看看为什么不能开箱即用.

装饰名,数据布局和标准库

最明显原因是:语法.C++编译器不理解Rust,Rust编译器也不理解C++.
因此,A语言都无法分辨出B语言提供了哪些函数或类.

现在,你也许会说:"但是,如果我使用C++.h文件来导出函数和类到其他.cpp文件,我当然也可以制作一个.h文件,来告诉C++有个Rustfn foo()函数在那里!

但还有些细节.
互操作性的第一个主要障碍是装饰名.你当然可创建一个带void foo();前向声明的.h文件,但C++编译器会找1个叫_Z3foov的符号,而Rust编译器会装饰fn foo()_ZN10rustmodule3foo17hdf3dc6f68b54be51E.
开始时是可以编译C++代码的,但是一旦到达链接阶段,链接器就无法找到_Z3foov,因为它不存在.

显然,需要在一侧或另一侧改变行为方式.

第二个主要障碍数据布局.总之,不同编译器可能会在内存不同位置,放置字段来声明相同结构字段,以按不同方式处理声明.

第三个也是最后的障碍是标准库.如果要返回std::stringC++函数,Rust无法理解它.相反,要实现某种转换C++串为Rust串的转换器.

同样,除非转换RustVec对象为C++理解的内容,否则,无法在C++中使用它.

看看如何解决第一个装饰名问题.

extern"C"及为什么它很糟糕

简单方法是使用几乎每种语言都有的外部"C"功能:

//文件:`main.cpp`
#include "rustmodule.h"
//或在理想的`C++20`世界中:
//import rustmodule;
int main()
{foo();return 0;
}
//-----------
//文件:`rustmodule.h`
#pragma once
extern "C" void foo();
//-----------
//文件:`rustmodule.rs`
#[no_mangle]
pub extern "C" fn foo() {println!("Hello from Rust");
}

(假设链接了所有正确的标准库),这会编译和运行!但为什么extern"C"很糟糕?好吧,用extern"C",你放弃了:

函数重载

类方法

模板

我想要可直接探测这些功能人类可读的包装器!
此外,我不想更改现有源码,即必须去掉丑陋的#[no_mangle]pub extern"C"!

用D

D是一个自2001年以来一直存在的语言.虽然它与C++源码不兼容,但它类似C++.我个人喜欢D的直观语法和强大的功能,但对,把RustC++粘合在一起中,D脱颖而出有两个原因:extern(C++)pragma(mangle,"foo").

使用extern(C++),可告诉D对符号使用C++装饰名.因此,编译以下代码:

//文件:`FOO.cpp`
#include <iostream>
void bar();
void foo()
{std::cout << "Hello from C++\n";bar();
}
//-----------
//文件:`main.d`
import std.stdio;
extern(C++) void foo();
extern(C++) void bar()
{writeln("Hello from D");
}
void main()
{foo();
}

然而,更好了:现在可用pragma(mangle,"foo")手动覆盖想要的名字!因此,编译以下代码:

//文件:`main.d`
import std.stdio;
pragma(mangle, "_ZN10rustmodule3foo17h18576425cfc60609E") void foo();
pragma(mangle, "bar_d_function") void bar()
{writeln("Hello from D");
}
void main()
{foo();
}
//-----------
//文件:`rustmodule.rs`
pub fn foo() {println!("Hello from Rust");unsafe {bar();}
}
extern {#[link_name = "bar_d_function"] fn bar();
}

使用pragma(mangle,"foo"),不仅可告诉D,Rust是如何装饰函数名的,还可创建一个Rust可见的函数!
为什么必须告诉Rust来覆盖bar()装饰.这是因为Rust显然不会对在extern块中的bar()应用装饰名;

测试中,甚至按外部"Rust"标记也没用.

为什么不用Rust装饰名覆盖而用D.好吧,Rust只允许按extern函数的前向声明覆盖混杂,所以在Rust中,不能按C++函数定义你的函数.

D作为胶水

现在,可用D将基本示例粘合在一起:

//文件:`main.cpp`
#include "rustmodule.h"
//或在理想的`C++20`世界中:
//import rustmodule;
int main()
{foo();return 0;
}
//-----------
//文件:`rustmodule.h`
#pragma once
//这是在`Rust`中
void foo();
//-----------
//文件:`rustmodule.rs`
pub fn foo() {println!("Hello from Rust");
}
//-----------
//文件:`glue.d`
@nogc:
//这是`Rust`函数.
pragma(mangle, "_ZN10rustmodule3foo17h18576425cfc60609E") void foo_from_rust();
//它按别名向`C++`公开.
extern(C++) void foo()
{foo_from_rust();
}

此例中,当main()C++调用foo()时,它是在调用一个调用Rust函数的D函数.它有点丑陋,但它可能,让C++Rust代码都不变就工作的代码.

自动化胶水

不过,没人愿意编写一个巨大的D文件来组C++Rust件粘合在一起.事实上,甚至没有人愿意手写C++头文件.
因此,我创建了叫polyglot的概念验证工具,它可扫描C++代码并生成包装器以供RustD使用.
下一期,探讨语言如何克服互操作性其他两个主要障碍.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/208429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gitee配置

注册配置gitee Gitee官网 进入官网之后&#xff0c;有账号直接登录&#xff0c;没有账号注册一个新的账号 下载安装git客户端 官网地址 下载完成&#xff0c;一路直接点击安装直接安装成功 检查是否安装成功 鼠标留在桌面–>右击–>出现Git GUI Here/Git Bash Her…

windows系统nodeJs报错node-sass npm ERR! command failed

报错信息 npm WARN deprecated request2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 npm WARN deprecated tar2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asa…

国科大通信原理复习

CH4-信源的数字化 26. 信源编码的基本方法和分类 27. 无失真编码和有失真编码的区别 无失真编码能够完全一模一样的恢复到原信号。 有失真编码则不行。 28. 信息量和熵的定义 29. 离散信源的最大熵定理 n表示所有符号的种类&#xff0c;比如对于二进制码字&#xff0c;Rbit对…

云计算ACP认证考试题库0-100

0001.单选题:阿里云的云盾会检查通过公共互联网登录云服务器ECS的来源IP,登录方式包括SSH和远程桌面,当来自某个IP的登录请求出现多次密码错误的情况时,会发出”ECS遭遇密码暴力破解”的报警,当收到这个报警后,最安全的处理方法应该是。 A.通知自己业务平台的所有用户立即修改…

基于支持向量机SVM的新鲜度等级预测,基于自适应粒子群优化长短期神经网络的新鲜度等级预测

目录 背影 支持向量机SVM的详细原理 SVM的定义 SVM理论 粒子群算法原理 SVM应用实例,基于支持向量机SVM的新鲜度等级预测,基于自适应粒子群优化长短期神经网络的新鲜度等级预测 代码 结果分析 展望 完整代码:基于支持向量机SVM的新鲜度等级预测,基于自适应粒子群优化长短期…

SpringBoot+线程池实现高频调用http接口并多线程解析json数据

场景 SpringbootFastJson实现解析第三方http接口json数据为实体类(时间格式化转换、字段包含中文)&#xff1a; SpringbootFastJson实现解析第三方http接口json数据为实体类(时间格式化转换、字段包含中文)-CSDN博客 Java中ExecutorService线程池的使用(Runnable和Callable多…

MindOpt APL:一款适合优化问题数学建模的编程语言

什么是建模语言 建模语言是一种描述信息或模型的编程语言&#xff0c;在运筹优化领域&#xff0c;一般是指代数建模语言。 比如要写一个线性规划问题的建模和求解&#xff0c;可以采用C、Python、Java等通用编程语言来实现计算机编程&#xff08;码代码&#xff09;&#xff0…

nodejs微信小程序+python+PHP的黄山旅游景点购票系统设计与实现-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

要求CHATGPT高质量回答的艺术:提示工程技术的完整指南—第 28 章:圣杯 = 专家 + ChatGPT 的协同作用

要求CHATGPT高质量回答的艺术&#xff1a;提示工程技术的完整指南—第 28 章&#xff1a;圣杯 专家 ChatGPT 的协同作用 ​ 这就像是从 ChatGPT 或其他生成式人工智能中获得高质量答案的圣杯。因为光知道怎么问&#xff08;提示工程技术&#xff09;还不够&#xff0c;还要知…

harmonyOS开发技巧(二)——沉浸式以及状态栏高

1. 设置沉浸式&#xff1a;win.setWindowLayoutFullScreen(true); 2. 获取状态栏的高&#xff1a;win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)以及win.on(avoidAreaChange, (data) > {})。 import UIAbility from ohos.app.ability.UIAbility; import wind…

联邦多任务蒸馏助力多接入边缘计算下的个性化服务 | TPDS 2023

联邦多任务蒸馏助力多接入边缘计算下的个性化服务 | TPDS 2023 随着移动智能设备的普及和人工智能技术的发展,越来越多的分布式数据在终端被产生与收集&#xff0c;并以多接入边缘计算(MEC)的形式进行处理和分析。但是由于用户的行为模式与服务需求的多样,不同设备上的数据分布…

复亚消防无人机 智能守护浙江安防

在党中央高度重视防灾减灾救灾工作的背景下&#xff0c;浙江省深化消防救援保障体系建设&#xff0c;借助智慧消防举措&#xff0c;提高了城市的战勤保障能力。特别是在古城区&#xff0c;复亚助力浙江打造智慧消防系统&#xff0c;通过消防无人机全自动飞行系统&#xff0c;成…

ALTERNET STUDIO 9.1 Crack

ALTERNET STUDIO 9.1 发布 宣布 AlterNET Studio 9.1 版本今天上线。AlterNET Studio 9.0 是一个中期更新&#xff0c;重点是改进我们所有的组件库。 以下是 AlterNET Studio 9.1 的发布亮点&#xff1a; Roslyn C# 和 Visual Basic 解析器现在支持代码修复/代码重构。 代码修复…

全景万店通打造掌上智慧生活助手,助力店铺全景引流

随着网络经济的崛起&#xff0c;新一代的消费群体的消费习惯逐渐变得富有个性化&#xff0c;因此他们对于传统的营销方式具有视觉疲劳&#xff0c;传统广告的效果也越发微小&#xff0c;但是请明显来代言&#xff0c;成本又十分高昂&#xff0c;那么还有什么引流好方法呢&#…

MySQL之数据库的创建指令

创建数据库 #创建数据库指令&#xff1a; CREATE DATABASE hsp_db1 #创建名字为关键字的数据库&#xff0c;为规避关键字&#xff0c;可以使用反引号 CREATE DATABASE CREATE#删除数据库指令&#xff1a; DROP DATABASE hsp_db1 DROP DATABASE CREATE如果不指定在这里插入代码片…

Linux--学习记录(2)

解压命令&#xff1a; gzip命令&#xff1a; 参数&#xff1a; -k&#xff1a;待压缩的文件会保留下来&#xff0c;生成一个新的压缩文件-d&#xff1a;解压压缩文件语法&#xff1a; gzip -k pathname(待压缩的文件夹名)gzip -kd name.gz&#xff08;待解压的压缩包名&#x…

Python中的深拷贝和浅拷贝的区别

目录 一、深拷贝和浅拷贝的概念 二、Python中的深拷贝和浅拷贝实现 三、深拷贝和浅拷贝的区别及适用场景 四、如何选择深拷贝和浅拷贝 五、总结 在Python中&#xff0c;深拷贝和浅拷贝是非常重要的概念&#xff0c;它们在处理对象和数据结构时有着截然不同的行为。理解深拷…

MySQL-DATE_FORMAT()函数

在 SQL 中&#xff0c;DATE_FORMAT() 函数是用于将日期时间值格式化为指定格式的函数。它允许你根据自己的需求将日期时间值转换成各种不同的字符串表示形式。以下是 DATE_FORMAT() 函数的用法和示例&#xff1a; DATE_FORMAT() 函数的基本用法&#xff1a; DATE_FORMAT() 函…

概率测度理论方法(第 2 部分)

一、说明 欢迎回到这个三部曲的第二部分&#xff01;在第一部分中&#xff0c;我们为测度论概率奠定了基础。我们探索了测量和可测量空间的概念&#xff0c;并使用这些概念定义了概率空间。在本文中&#xff0c;我们使用测度论来理解随机变量。 作为一个小回顾&#xff0c;在第…

Azure云WAF服务的CRS规则和DRS规则区别

在Azure中&#xff0c;WAF&#xff08;Web Application Firewall&#xff09;是一种用于保护 Web 应用程序免受常见 Web 攻击的服务。WAF 支持两种类型的规则&#xff1a;CRS&#xff08;Core Rule Set&#xff09;规则和 DRS&#xff08;Default Rule Set&#xff09;规则。以…