C 中的不相交聯合
目前還不清楚如何在 C 中表達此 Haskell 類型:
data Tree = Leaf Int | Inner Tree Tree
與 Haskell 和 Rust 等語言不同,C 缺乏對
的內建支持
不相交的聯合。然而,如果我們願意做一些額外的輸入,它確實提供了代表它們所需的所有成分。
首先要認識到的是,不相交的並集包括:
- 許多不同的變體
- 每個都有一些與之關聯的數據。
在我們的二元樹範例中,我們有兩個變體:「葉子」和「內部」。葉變數儲存單一整數(其資料),內部變數儲存兩棵樹(代表其左子樹和右子樹)。
我們可以使用具有兩個字段的結構在 C 中表示這樣的動物:
- “類型標籤”,通常是整數,指示所表示的變體。
- data 字段,用於儲存與變體相關的資料。
使用枚舉定義不同的變體類型標籤很方便:
enum tree_type { TREE_LEAF, TREE_INNER, };
儲存資料怎麼樣?這就是工會存在要解決的問題類型。
工會
聯合只是一塊能夠儲存多種不同類型資料的記憶體。例如,這是一個可以儲存 32 位元 int 或 5 個字元數組的聯合。
union int_or_chars { int num; char letters[5]; };
類型為 union int_or_chars 的變數可以在任何特定時間保存 int 或 5 個字元的陣列(但不能同時儲存):
union int_or_chars quux; // We can store an int: quux.num = 42; printf("quux.num = %d\n", quux.num); // => quux.num = 42 // Or 5 chars: quux.letters[0] = 'a'; quux.letters[1] = 'b'; quux.letters[2] = 'c'; quux.letters[3] = 'd'; quux.letters[4] = 0; printf("quux.letters = %s\n", quux.letters); // => quux.letters = abcd // But not both. The memory is "shared", so the chars saved above are // now being interpreted as an int: printf("quux.num = %x\n", quux.num); // quux.num = 64636261 return 0;
像 union int_or_chars 這樣的聯合擁有足夠大的記憶體區塊可供使用,可以容納其最大的成員。這是顯示其工作原理的示意圖:
+ ---- + ---- + ---- + ---- + ---- + | byte | | | | | + ---- + ---- + ---- + ---- + ---- + |<-- int uses these 4 -->| |<-- array of chars uses all 5 -->|
這有助於解釋為什麼在我們在 quux 中儲存字元數組後列印 quux.num 會導致「垃圾」:它不是垃圾,而是字串「abcd」被解釋為整數。 (在我的機器上,quux.num 以十六進位列印為64636261。字元「a」的ASCII 值為0x61,「b」的值為0x62,「c」為0x63,「d」為0x64。由於我的處理器是小端字節序,所以順序顛倒了。
關於聯合的最後一點,您可能會對 sizeof 報告的大小感到驚訝:
printf("%ld\n", sizeof(union int_or_chars)); // => 8
返回二元樹
我們現在準備繼續將二元樹類型從 Haskell 轉換為 C。我們已經定義了一個枚舉來表示變體的類型。現在我們需要一個聯合來儲存其資料:
union tree_data { int leaf; struct inner_data inner; };
struct inner_data { struct tree *left; struct tree *right; };
指向其左子節點和右子節點的指標。間接是必要的,因為否則結構樹將沒有固定的大小。
這些部分就位後,我們就可以定義我們的樹類型了:
enum tree_type { TREE_LEAF, TREE_INNER, }; struct tree; struct inner_data { struct tree *left; struct tree *right; }; union tree_data { int leaf; struct inner_data inner; }; // A representation of a binary tree. struct tree { enum tree_type type; union tree_data data; };
讓我們寫一些函式來建構樹:
// Construct a leaf node. struct tree *leaf(int value) { struct tree *t = malloc(sizeof(*t)); t->type = TREE_LEAF; t->data.leaf = value; return t; } // Construct an inner node. struct tree *inner(struct tree *left, struct tree *right) { struct tree *t = malloc(sizeof(*t)); t->type = TREE_INNER; t->data.inner.left = left; t->data.inner.right = right; return t; }
void print_tree(struct tree *t) { switch (t->type) { case TREE_LEAF: printf("%d", t->data.leaf); return; case TREE_INNER: printf("("); print_tree(t->data.inner.left); printf(" "); print_tree(t->data.inner.right); printf(")"); return; } }
Inner (Inner (Leaf 1) (Leaf 2)) (Leaf 3)
inner(inner(leaf(1), leaf(2)), leaf(3));
struct tree *t = inner(inner(leaf(1), leaf(2)), leaf(3)); print_tree(t); // => ((1 2) 3)
-- Check if a value is in a tree. search :: Int -> Tree -> Bool search v (Leaf w) = v == w search v (Inner l r) = search v l || search v r
// Check if a value is in a tree. int search(int value, struct tree *t) { switch (t->type) { case TREE_LEAF: return t->data.leaf == value; case TREE_INNER: return ( search(value, t->data.inner.left) || search(value, t->data.inner.right) ); } }
權衡
我們最後稍微題外話一下替代表示中涉及的權衡。具體來說,假設不是:
union tree_data { int leaf; struct inner_data inner; };
union tree_data { int leaf; struct inner_data *inner; // ^ The difference. };
指標。因此,第一個聯合體稍大一些,為 16 字節,而我的機器上的指標版本為 8 個位元組。不幸的是,受影響的不僅僅是內部節點:葉節點使用相同的 16 位元組聯合,但僅儲存單一(4 位元組)int。感覺有點浪費。
然而,這並不是故事的全部。每次訪問內部節點的左子節點和右子節點時,我們都會為額外的間接尋址付出代價:讀取不一定便宜,特別是在指向的記憶體未快取的情況下。我懷疑這裡提出的主要方法在大多數情況下是一個更好的起點,並且嘗試削減一些字節(白色導致額外的讀取)是不值得的,直到它成為現實。
以上是C 中的不相交聯合的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

C#和C 的歷史與演變各有特色,未來前景也不同。 1.C 由BjarneStroustrup在1983年發明,旨在將面向對象編程引入C語言,其演變歷程包括多次標準化,如C 11引入auto關鍵字和lambda表達式,C 20引入概念和協程,未來將專注於性能和系統級編程。 2.C#由微軟在2000年發布,結合C 和Java的優點,其演變注重簡潔性和生產力,如C#2.0引入泛型,C#5.0引入異步編程,未來將專注於開發者的生產力和雲計算。

C#和C 的学习曲线和开发者体验有显著差异。1)C#的学习曲线较平缓,适合快速开发和企业级应用。2)C 的学习曲线较陡峭,适用于高性能和低级控制的场景。

靜態分析在C 中的應用主要包括發現內存管理問題、檢查代碼邏輯錯誤和提高代碼安全性。 1)靜態分析可以識別內存洩漏、雙重釋放和未初始化指針等問題。 2)它能檢測未使用變量、死代碼和邏輯矛盾。 3)靜態分析工具如Coverity能發現緩衝區溢出、整數溢出和不安全API調用,提升代碼安全性。

C 通過第三方庫(如TinyXML、Pugixml、Xerces-C )與XML交互。 1)使用庫解析XML文件,將其轉換為C 可處理的數據結構。 2)生成XML時,將C 數據結構轉換為XML格式。 3)在實際應用中,XML常用於配置文件和數據交換,提升開發效率。

使用C 中的chrono庫可以讓你更加精確地控制時間和時間間隔,讓我們來探討一下這個庫的魅力所在吧。 C 的chrono庫是標準庫的一部分,它提供了一種現代化的方式來處理時間和時間間隔。對於那些曾經飽受time.h和ctime折磨的程序員來說,chrono無疑是一個福音。它不僅提高了代碼的可讀性和可維護性,還提供了更高的精度和靈活性。讓我們從基礎開始,chrono庫主要包括以下幾個關鍵組件:std::chrono::system_clock:表示系統時鐘,用於獲取當前時間。 std::chron

C 的未來將專注於並行計算、安全性、模塊化和AI/機器學習領域:1)並行計算將通過協程等特性得到增強;2)安全性將通過更嚴格的類型檢查和內存管理機制提升;3)模塊化將簡化代碼組織和編譯;4)AI和機器學習將促使C 適應新需求,如數值計算和GPU編程支持。

1)c relevantduetoItsAverity and效率和效果臨界。 2)theLanguageIsconTinuellyUped,withc 20introducingFeaturesFeaturesLikeTuresLikeSlikeModeLeslikeMeSandIntIneStoImproutiMimproutimprouteverusabilityandperformance.3)

DMA在C 中是指DirectMemoryAccess,直接內存訪問技術,允許硬件設備直接與內存進行數據傳輸,不需要CPU干預。 1)DMA操作高度依賴於硬件設備和驅動程序,實現方式因係統而異。 2)直接訪問內存可能帶來安全風險,需確保代碼的正確性和安全性。 3)DMA可提高性能,但使用不當可能導致系統性能下降。通過實踐和學習,可以掌握DMA的使用技巧,在高速數據傳輸和實時信號處理等場景中發揮其最大效能。
