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.pswp.cn/news/208429.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/208429.shtml
英文地址,請注明出處:http://en.pswp.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;規則。以…