検索

Disjoint Unions in C

C でこの Haskell 型を表現する方法はすぐにはわかりません:

data Tree = Leaf Int | Inner Tree Tree

Haskell や Rust などの言語とは異なり、C には
の組み込みサポートがありません。 素の結合。ただし、もう少し入力を加えても、表現するために必要なすべての要素が提供されます。

最初に理解すべきことは、素結合は次のもので構成されているということです。

  • さまざまな バリアント
  • それぞれに、いくつかの データが関連付けられています。

バイナリ ツリーの例には、「リーフ」と「インナー」という 2 つのバリアントがあります。リーフ バリアントは 1 つの整数 (そのデータ) を格納し、内部バリアントは 2 つのツリー (その左と右の子を表す) を格納します。

このような動物は、2 つのフィールドを持つ構造体を使用して C で表現できます。

  1. どのバリアントが表現されているかを示す「型タグ」。通常は整数です。
  2. バリアントに関連付けられたデータを保存する 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 |      |      |      |      |
+ ---- + ---- + ---- + ---- + ---- +
||
||

これは、quux に文字の配列を格納した後、quux.num を印刷すると「ガベージ」が発生する理由を説明するのに役立ちます。これはガベージではなく、文字列「abcd」が整数として解釈されたためです。 (私のマシンでは、quux.num は 64636261 と 16 進数で表示されます。文字「a」の ASCII 値は 0x61、「b」の値は 0x62、「c」は 0x63、「d」は 0x64 です。私のプロセッサはリトルエンディアンなので、順序が逆になります。)

共用体に関する最後の注意として、sizeof によって報告されるサイズに驚かれるかもしれません:

printf("%ld\n", sizeof(union int_or_chars));
// => 8

私のマシンでは、union int_or_chars 型のサイズは、予想されていた 5 バイトではなく、8 バイトです。私のプロセッサのアーキテクチャで規定されているアライメント要件のため、一部のパディングが追加されています。

二分木に戻る

これで、Haskell から C へのバイナリ ツリー型の変換を続行する準備が整いました。バリアントの型を表す enum をすでに定義しました。次に、データを保存するためのユニオンが必要です:

union tree_data {
        int leaf;
        struct inner_data inner;
};

ここで、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;
        }
}

これにより、Haskell 式を翻訳できるようになります。

Inner (Inner (Leaf 1) (Leaf 2)) (Leaf 3)

C に次のように変換します:

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.
};

最初のケースでは、共用体には struct inner_data が含まれますが、2 番目のケースでは、この構造体への ポインター が格納されます。その結果、最初の共用体は 16 バイトと少し大きくなります。これに対し、私のマシンのポインター バージョンでは 8 バイトです。残念ながら、影響を受けるのは内部ノードだけではありません。リーフ ノードはこれと同じ 16 バイトの共用体を使用しますが、単一 (4 バイト) int のみを格納します。ちょっともったいない気がします

しかし、それだけではありません。内部ノードの左右の子にアクセスするたびに、追加の間接的なコストを支払うことになります。特に、指すメモリがキャッシュされていない場合、読み取りは必ずしも安価であるとは限りません。

ここで紹介する主なアプローチは、ほとんどの場合、より良い出発点であり、数バイト (追加の読み取りが発生する白) を削減しようとしても、それが実現するまでは価値がないと思われます。

以上がC での素の共用体の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
CおよびXML:プロジェクトにデータを統合しますCおよびXML:プロジェクトにデータを統合しますMay 10, 2025 am 12:18 AM

CプロジェクトにXMLを統合することは、次の手順を通じて達成できます。1)PUGIXMLまたはTinyXMLライブラリを使用してXMLファイルを解析および生成すること、2)解析のためのDOMまたはSAXメソッドを選択、3)ネストされたノードとマルチレベルのプロパティを処理する、4)デバッグ技術と最高の慣行を使用してパフォーマンスを最適化します。

CでXMLを使用する:ライブラリとツールのガイドCでXMLを使用する:ライブラリとツールのガイドMay 09, 2025 am 12:16 AM

XMLは、特に構成ファイル、データストレージ、ネットワーク通信でデータを構成するための便利な方法を提供するため、Cで使用されます。 1)tinyxml、pugixml、rapidxmlなどの適切なライブラリを選択し、プロジェクトのニーズに従って決定します。 2)XML解析と生成の2つの方法を理解する:DOMは頻繁にアクセスと変更に適しており、SAXは大規模なファイルまたはストリーミングデータに適しています。 3)パフォーマンスを最適化する場合、TinyXMLは小さなファイルに適しています。PugixMLはメモリと速度でうまく機能し、RapidXMLは大きなファイルの処理に優れています。

C#およびC:さまざまなパラダイムの探索C#およびC:さまざまなパラダイムの探索May 08, 2025 am 12:06 AM

C#とCの主な違いは、メモリ管理、多型の実装、パフォーマンスの最適化です。 1)C#はゴミコレクターを使用してメモリを自動的に管理し、Cは手動で管理する必要があります。 2)C#は、インターフェイスと仮想方法を介して多型を実現し、Cは仮想関数と純粋な仮想関数を使用します。 3)C#のパフォーマンスの最適化は、構造と並列プログラミングに依存しますが、Cはインライン関数とマルチスレッドを通じて実装されます。

C XML解析:テクニックとベストプラクティスC XML解析:テクニックとベストプラクティスMay 07, 2025 am 12:06 AM

DOMおよびSAXメソッドを使用して、CのXMLデータを解析できます。1)DOMのXMLをメモリに解析することは、小さなファイルに適していますが、多くのメモリを占有する可能性があります。 2)サックス解析はイベント駆動型であり、大きなファイルに適していますが、ランダムにアクセスすることはできません。適切な方法を選択してコードを最適化すると、効率が向上する可能性があります。

特定のドメインのc:その拠点の調査特定のドメインのc:その拠点の調査May 06, 2025 am 12:08 AM

Cは、高性能と柔軟性のため、ゲーム開発、組み込みシステム、金融取引、科学的コンピューティングの分野で広く使用されています。 1)ゲーム開発では、Cは効率的なグラフィックレンダリングとリアルタイムコンピューティングに使用されます。 2)組み込みシステムでは、Cのメモリ管理とハードウェア制御機能が最初の選択肢になります。 3)金融取引の分野では、Cの高性能はリアルタイムコンピューティングのニーズを満たしています。 4)科学的コンピューティングでは、Cの効率的なアルゴリズムの実装とデータ処理機能が完全に反映されています。

神話を暴く:Cは本当に死んだ言語ですか?神話を暴く:Cは本当に死んだ言語ですか?May 05, 2025 am 12:11 AM

Cは死んでいませんが、多くの重要な領域で栄えています。1)ゲーム開発、2)システムプログラミング、3)高性能コンピューティング、4)ブラウザとネットワークアプリケーション、Cは依然として主流の選択であり、その強力な活力とアプリケーションのシナリオを示しています。

C#対C:プログラミング言語の比較分析C#対C:プログラミング言語の比較分析May 04, 2025 am 12:03 AM

C#とCの主な違いは、構文、メモリ管理、パフォーマンスです。1)C#構文は最新であり、LambdaとLinqをサポートし、CはC機能を保持し、テンプレートをサポートします。 2)C#はメモリを自動的に管理し、Cは手動で管理する必要があります。 3)CパフォーマンスはC#よりも優れていますが、C#パフォーマンスも最適化されています。

Cを使用したXMLアプリケーションの構築:実用的な例Cを使用したXMLアプリケーションの構築:実用的な例May 03, 2025 am 12:16 AM

tinyxml、pugixml、またはlibxml2ライブラリを使用して、CでXMLデータを処理できます。1)XMLファイルを解析する:DOMまたはSAXメソッドを使用し、DOMは小さなファイルに適しており、SAXは大きなファイルに適しています。 2)XMLファイルを生成:データ構造をXML形式に変換し、ファイルに書き込みます。これらの手順を通じて、XMLデータを効果的に管理および操作できます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

SublimeText3 Linux 新バージョン

SublimeText3 Linux 新バージョン

SublimeText3 Linux 最新バージョン

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境