欧美vvv,亚洲第一成人在线,亚洲成人欧美日韩在线观看,日本猛少妇猛色XXXXX猛叫

新聞資訊

    作為一門面向過程、抽象化的通用程序設計語言,C 常被用于系統開發、游戲引擎等場景中。不過,近日 Rust、Swift 資深專家 Aria 發布了一篇文章《C 不再是一種編程語言》的文章,在 News 上引起了開發者激烈的討論。

    Aria 和其朋友 都一致認為,C 語言的 ABI 接口非常令人失望,并試圖進行修復。盡管如此,但二人對 C 語言失望的點又各自不同,那具體產生了哪些分歧?筆者將對原文進行編譯,一探究竟。

    原文鏈接:

    HN:

    整理 | 于軒

    出品 | 程序人生 (ID:coder _life)

    在文章伊始,Aria表示其正在嘗試從實質上改善使用C以外的任何語言的條件,而試圖從本質上改善使用C本身作為編程語言的條件。

    也許大家會非常好奇,以上和C語言到底有什么關系?

    Aria認為,如果C真的是一種編程語言,那就和它無關。不幸的是,它并不再是一門編程語言了。這似乎與C語言由數十億種實現方式和失敗的層次結構,導致它的定義方式非常糟糕的事實有關。C已經被提升到一個具有威望和權力的角色,它的統治是絕對和永恒的,以至于它扭曲了開發者與該語言之間的對話方式。當下,C是編程的通用語言,我們都必須學C,這也導致C不再只是一種編程語言,它成了每一種通用編程語言都需要遵守的協議。

    這實際有點像是關于整個“C是一個不可捉摸的實現定義混亂” 。但僅因為它讓我們不得不使用這個協議,這就變成了一個更大的噩夢。

    外部功能接口

    首先我們從技術層面來聊一下。假如你已經完成了新語言設計,對Bappy Paws//Fins有一流的支持。這是一種神奇的語言,將徹底改變人們的編程方式。

    但現在需要讓它真正做一些有用的事情。比如接受用戶輸入、輸出,或者字面上的任何可觀察之類的東西。如果你想讓該語言編寫的程序與主流操作系統兼容,那就需要與操作系統的界面進行交互。聽說Linux上的一切都“只是一個文件”,所以一起在Linux上打開一個文件吧!

    OPEN(2), , creat - open and a # open(const char *, int flags);int open(const char *, int flags, mode);int creat(const char *, mode);int (int dirfd, const char *, int flags);int (int dirfd, const char *, int flags, mode);/* , in (2): */int (int dirfd, const char *,const *how, size); Test Macro for glibc (os(7)):

    ():Since glibc 2.10: >= glibc 2.10:

    這是,不是C,那Linux的接口在哪里?

    你說Linux中沒有接口是什么意思?好吧,當然是因為這是一種全新的語言,但你會添加一個,對嗎?那這時你就會發現,你好像必須使用他們給的東西。

    你將需要某種接口,讓語言能夠調用外部函數,就像外部函數接口FFI。然后你發現Rust也有C FFI,Swift也有,甚至也有。

    最后你會發現,每個人都必須學會C才能與主流的操作系統進行交互,然后當需要相互對話時,大家突然都用起了C。既然如此,為什么不直接用C來進行交互呢?

    現在C就變成了一種編程通用語言,不僅是一種編程語言,它還是一種協議了。

    與C進行交互涉及哪些內容?

    很明顯,基本上每種語言都必須學會與C進行交互,而且這種語言絕對是非常明確的。

    ""C是什么意思?它意味著以C頭文件的形式獲得接口類型和功能的描述,并以某種方式:

    那么,這里就有幾個問題:

    實際上無法解析一個C頭文件

    Aria曾斷言解析C基本上是不可能的,但有人說其實有很多工具可以讀取C頭文件,比如rust-。事實果真如此嗎?其實不然。

    使用來解析C和C++頭文件。要修改搜索的方式,請參閱clang-sys文檔。關于如何使用的更多細節,請參閱用戶指南。

    任何花費大量時間試圖快速解析C(++)頭文件的人都會很快放棄,然后讓一個C(++)編譯器來做這件事。請記住,有意義地解析C頭文件不僅僅是解析:你還需要解決#、和的問題!所以現在不僅要實現所有相關功能,還要實現所有平臺的頭文件解析邏輯,并且還需要想方設法找到!

    就拿Swift來說,它在與C進行互操作和資源方面擁有絕對優勢,它是由蘋果開發的一門編程語言,有效取代了-C,成為在其平臺上定義和使用系統API的主要語言。在這樣做的過程中,它比其他任何人都更想進一步實現ABI穩定和概念設計。

    它也是Aria見過的最支持FFI的語言之一。它可以本地導入(-)C(++)頭文件,并產生一個漂亮的本地Swift接口,其類型在邊界自動 "橋接 "到它們的Swift對等項(由于類型具有相同的ABI,所以通常是透明的)。

    Swift的許多開發者同時也是構建和維護Clang和LLVM的開發人員。這些人都是C及其衍生品方面的世界頂級專家。Doug 就是其中之一,他曾表達了對C FFI的看法:

    可以看出,即使是Swift也不想花時間解析C(++)頭文件。那么,如果你絕對不想讓C編譯器在編譯時解析和解決頭文件,你該怎么做呢?

    你需要手工翻譯??? 還是寫i64. long…?什么是long?

    C實際上沒有ABI

    好吧,這沒有什么好驚訝的:C語言中的整數類型,為了 “可移植性”而被設計成大小不固定。我們可以認為很奇怪,但這也不能幫助我們了解long的大小和對齊方式。

    有人說每個平臺都有標準化的調用約定和ABI,確實有,而且它們通常定義了C中關鍵原語的布局(并且有些不只是用C類型來定義調用約定,參考AMD64 SysV)。

    還有一個棘手的問題:架構并沒有定義ABI,操作系統也沒有。我們必須在一個特定的目標三元組上全力以赴,比如 “-pc--gnu”(不要和 "-pc--msvc "混淆)。經過測試,一共有176個三元組。

    > rustc --print -list

    -apple--apple--apple-ios--apple-ios--apple-tvos

    armv7--linux---linux---linux--uwp---uwp---wrs-

    ABI實在是太多了,因為測試中甚至沒有用到所有不同的調用約定,如 vs 或aapcs vs aapcs-vfp。

    但至少所有這些ABI和調用約定之類都可以用一種方便使用的機器可讀格式獲得。至少主流的C編譯器在特定目標三元組的ABI上達成了一致! 當然有一些奇怪的jank C編譯器,但Clang和GCC不是:

    > abi- --tests ui128 --pairs

    Test ui128::c:::: ui128::c:::: ui128::c:::: ui128::c:::: ui128::c:::: !test 57 arg3 field 0 : [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3A, 3B, 3C, 3D, 3E, 3F]: [38, 39, 3A, 3B, 3C, 3D, 3E, 3F, 40, 41, 42, 43, 44, 45, 46, 47]Test ui128::c:::: !test 58 arg3 field 0 : [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3A, 3B, 3C, 3D, 3E, 3F]: [38, 39, 3A, 3B, 3C, 3D, 3E, 3F, 40, 41, 42, 43, 44, 45, 46, 47]

    392 , 60 , 0 , 8

    上面是Aria在 20.04 x64上運行的FFI abi-,她在這個相當重要的、表現良好的平臺上測試了一些非常無聊的Demo。結果發現,一些整數參數在兩個由Clang和GCC編譯的靜態庫之間按值傳遞失敗了!

    Aria發現,Clang和GCC甚至不能就Linux x64上的ABI達成一致。

    Aria本來是為了檢查rustc中的錯誤,沒想到會在一個重要的、常用的ABI上發現兩大主流C編譯器的不一致。

    試圖馴服C

    Aria認為,可怕的是對C頭文件進行語義解析,只能由該平臺的C編譯器來完成。即使C編譯器告訴了你類型和如何理解注釋,但實際上你仍然不知道所有內容的大小/對齊/慣例。那如何與這些亂七八糟的東西進行互操作呢?Aria提供了兩種選擇。

    第一個選擇是完全放棄,將你的語言與C進行靈魂綁定,這可以是以下任何一種:

    即使做到上面這些,也不會讓你的編譯器走多遠,除非你的語言真的暴露了 long long,否則你將繼承C的巨大可移植性混亂。

    這就讓我們想到了第二個選擇:撒謊、欺騙和偷竊。

    如果這一切是無論如何都無法避免的災難,你還不如開始手工翻譯類型和接口定義,基本上就是我們每天在Rust中所做的事情。比如,人們使用rust-和自動化處理一些事,但很多時候,定義會被檢查或手工調整。因為人們不想浪費時間去嘗試的定制C構建系統可移植地工作。

    在Rust中,Linux x64上的是什么?

    pub type = i64;

    在Nim中,Linux x64上的long long是什么?

    {.: "long long", .} = int64

    很多代碼已經完全放棄將C保持在循環中,開始對核心類型的定義進行硬編碼。畢竟,它們顯然只是平臺ABI的一部分!他們要改變的大小嗎?這顯然是一個破壞ABI的變化!

    那正在研究的又是什么?

    我們討論過為何 不能被改變,因為如果我們從 long long(64位整數)改為 (128位整數),某個地方的二進制會失控使用錯誤的調用約定/返回約定。但有沒有一種方法,如果代碼選擇了它或其他東西,我們可以為較新的應用程序升級函數調用,而讓舊應用程序保持不變?讓我們編寫一些代碼,測試一下透明別名可以幫助ABI的想法。

    Aria提出了她的疑問:編程語言如何處理這種變化?如何指定與哪個版本的交互?如果你有一些C頭文件提到,它使用的是哪個定義?

    在此討論具有不同ABI的平臺的主要機制是目標三元組。你知道什么是目標三元組嗎?你知道基本上涵蓋了過去20年里所有主流桌面/服務器Linux發行版的--linux-gnu包括什么嗎?現在,雖然表面上可以針對這個目標進行編譯,并得到一個在所有這些平臺上都能“正常工作”的二進制文件,但Aria不相信有些程序會被編譯成大于。

    任何試圖做出這種改變的平臺都會成為一個新的--linux-gnu2目標三元組嗎?如果任何針對--linux-gnu編譯的東西都被允許在上面運行,這難道還不夠嗎?

    在不破壞ABI的情況下更改簽名

    "那又怎樣,C永遠不會再有進步嗎?"不!但也是!因為他們提供了糟糕的設計。

    老實說,進行ABI兼容的修改是一種藝術形式。這種藝術的一部分就是準備工作。具體來說,如果你準備好了,做出不破壞ABI的修改就會容易得多。

    正如的文章所指出的,像glibc(g是--linux-gnu中的gnu)早就明白了這一點,并使用符號版本化這樣的機制來更新簽名和API,同時為任何針對舊版本編譯的人保留舊版本。

    因此,如果你有 (),你告訴編譯器將其導出為,那么任何根據這個頭文件進行編譯的人,都會在他們的代碼中寫上,但針對鏈接。

    然后當你決定實際上應該使用時,你可以把 ()作為,但保留舊的定義作為。任何針對較新版本頭文件進行編譯的人都會高興地使用v2符號,而針對舊版本進行編譯的人則繼續使用v1!

    但是你仍然有一個兼容性的問題:任何用新頭文件編譯的人都不能與庫的舊版本進行鏈接,庫的V1版本根本沒有V2符號!因此,如果你想獲得熱門的新功能,你就要接受與舊系統的不兼容。

    不過這并不是什么大問題,它只是讓平臺供應商感到難過,因為沒有人能夠立即使用他們花了這么多時間做的東西。你不得不推出一個閃亮的新功能,然后讓大家等待它變得足夠普遍和成熟。但為了人們愿意依賴它并中斷對舊平臺的支持(或者愿意為它實施動態檢查和回退)時,你必須坐等幾年。

    如果你真的想讓人們立即升級,那就要談論向前兼容的問題。這讓舊版本的東西以某種方式與他們沒有概念的新功能一起工作。

    在不破壞ABI的情況下更改類型

    那除了可以改變一個函數的簽名,還可以改變類型布局嗎?Aria表示,這取決于你是如何暴露類型的。

    C真正奇妙的一個特點是,它可以讓你區分一個已知布局的類型和一個未知布局的類型。如果你只在C頭文件中前向聲明一個類型,那么任何與之交互的用戶代碼都不被“允許”知道該類型的布局,并且必須一直在指針后面不透明地處理它。

    所以你可以做一個像* ()和(*)的API,然后使用同樣的符號版本技巧來暴露和符號,任何時候你想改變這個布局,你就在所有與該類型交互的東西上增加版本。類似地,你在、和一些類型定義中保留了一些,以確保人們使用“正確”的類型。這樣就可以在不同的版本之間改變類型的布局。

    如果多個東西建立在你的庫之上,然后開始用不透明類型相互交談,壞事就會發生:

    如果lib1和lib2針對庫的不同版本進行了編譯,那么就會被輸入到中!你有兩個選擇來處理這個問題:

    1.說這是被禁止的,責備那些無論如何都要這么做的人,然后傷心

    2.以一種向前兼容的方式設計,這樣混合就可以了

    常見的前向兼容技巧包括:

    案例研究:

    微軟是這種向前兼容的大師,甚至可以實現在架構之間保持布局兼容。Aria最近正在處理的一個例子是.h中的。

    這個API描述了一個有版本的值列表。該列表以這種類型開始:

    { ; ; ; ;} , *;

    其中:

    而事實上,微軟實際上有理由使用這種版本方案,并定義了兩個版本的數組元素:

    { ;RVA ;RVA ; ; ; ; ;} , *; { ;RVA ;RVA ; ; ; ; ;RVA ; ;} , *;

    // The . ; *;

    這些結構的實際細節不是很有趣,除了:

    這是一個堅不可摧的向前兼容的龐然大物。它們對填充非常小心,它甚至在32位和64位之間有相同的布局 (這實際上是非常重要的,因為你希望一個架構上的處理器能夠處理來自每個架構的)。

    案例研究:

    Aria對這種情況不是很熟悉,但在研究歷史上的glibc中斷時,她在LWN上看到了一篇很棒的文章:《glibc s390 ABI中斷》,她假設它是準確的。

    事實證明,glibc曾經破解過類型的ABI,至少在s390上。根據這篇文章的描述,它是混亂的。

    特別是他們改變了/使用的保存狀態類型的布局,即?,F在,他們知道這是一個破壞ABI的變化,所以他們做了負責任的符號版本化的事情。

    但并不是一個不透明的類型,其他東西都在內聯地存儲這個類型的實例,比如Perl的運行時間。不用說,這個相對晦澀的類型已經滲透到許多二進制文件中去了,最終的結論是,的所有東西都需要重新編譯!

    這篇文章甚至討論了將libc版本升級以應對這種情況的可能性:

    在像這樣的混合ABI環境中,SO名稱碰撞導致兩個libc被加載并爭奪相同的符號命名空間,而解析(以及因此選擇ABI)則由ELF插值和范圍規則決定。這真是一場噩夢。這可能是一個比告訴大家重建并繼續生活更糟糕的解決方案。

    真的能改變嗎?

    在Aria看來,不完全是。就像一樣,它不是一個不透明的類型,這意味著它被內聯到大量的隨機結構中,被認為具有大量其他語言和編譯器的特定表示,并且可能是大量公共接口的一部分。而這些接口并不在libc、Linuxc語言流程圖生成器,甚至不在發行版維護者的控制之下。

    當然,libc可以適當地使用符號版本技巧來使其API與新的定義兼容,但改變像這樣的基本數據類型的大小,是在一個平臺的大生態系統中尋求混亂。

    Aria希望被證明自己是錯誤的,但據她所知,做出這樣的改變需要一個新的目標三元組,并且不允許任何為舊ABI構建的二進制/庫在這個新三元組上運行。當然有人可以做這些工作,但Aria并不羨慕任何這樣做的發行版。

    即使如此,面臨的還有x64的int問題:這是一個非常基本的類型,而且長期以來一直是這種大小,無數的應用程序可能對它有奇怪的無法察覺的假設。這就是為什么int在x64上是32位的,盡管它應該是64位的:int是32位的時間太長了,以至于完全無望將軟件更新到新的大小,盡管它是一個全新的架構和目標三元組。

    Aria再次希望自己是錯的,但是人們有時犯的錯誤如此嚴重,以至于根本無法挽回。如果C語言是一種獨立的編程語言?當然可以去做。但它不是,它是一個協議,還是我們必須使用的糟糕的協議。

    就算C征服了世界,但也許它再也得不到好東西了。

    END

    《》全面上市,對話世界級大師c語言流程圖生成器,報道中國IT行業創新創造

    —點這里↓↓↓記得關注標星哦~—

    一鍵三連 「分享」「點贊」「在看」

    成就一億技術人

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有