4

そのため、VM 実行用にバイトコードにコンパイルし、ネイティブ バイナリにコンパイルするための中間言語として C にコンパイルするプログラミング言語を開発しています。私が C を選んだのは、それが十分に低レベルで移植性があり、既存のコンパイラを再利用することで多大な労力を節約し、さまざまなプラットフォームとその奇妙な点ごとにコンパイラをアセンブリに記述する必要がないためです。

しかし、既存のコンパイラには欠点があり、その 1 つは循環依存の問題です。厄介な前方宣言を使用せずに (C/C++ とは異なり)、循環依存関係をエレガントな方法で解決したいと考えています。また、ポインターや余分な間接参照や無駄なメモリを使用したり、宣言を定義から分離したりする必要もありません...つまり、一部のプログラミング言語のように、この問題を開発者から取り除きます。

私の見方では、これに関する現在の C/C++ コンパイラの主な問題は、プログラマーの意図が既にコードで表現されているため、実際には未来ではないにもかかわらず、「未来を見る」ことができないことです。私のコンパイラにはその問題はありません。 、解析の進行状況の特定のポイントを超えて何も知らないわけではなく、循環依存関係を持つオブジェクトのサイズを認識し、適切なオフセットなどを計算できます。

継承された構造のメンバーの「インライン展開」を単純に行う「偽の」継承を既に実装しているので、同じアプローチを使用して実際に偽の集約もできると考えています。最も基本的で単純な例では:

typedef struct {
    int a;
} A;

typedef struct {
    A a;
    int b;
} B;

になります:

typedef struct {
    int A_a;
    int b;
} B;

コンパイラは少し「変換」を行います。

B b;
b.a.a = 7;

になります:

b.A_a = 7;

同様に、すべての構造は、プリミティブ型のみを含む単一のルート構造に折りたたまれます。このように、事前にサイズが不明な構造体で使用されるタイプはまったくないため、定義の順序は無関係になります。当然のことながら、この混乱はユーザーから隠され、ユーザー側が構造化されて読みやすい状態に保たれている間、コンパイラーの「目」のみに表示されます。言うまでもなく、通常の C/C++ コードとの互換性のためにバイナリ フットプリントが保持されます。折りたたまれた構造は、集約または継承を使用する通常の構造と同じバイナリです。

だから私の質問は: これは健全なアイデアのように聞こえますか? 私が行方不明になっている可能性のあるものはありますか?

編集:「鶏が先か卵が先か」の論理パラドックスではなく、循環依存関係に関する C/C++ 関連の問題のみを解決することを目的としています。何らかの形の無限ループにつながることなく、2 つのオブジェクトが互いを含むことは明らかに不可能です。

4

1 に答える 1

1

プリミティブメンバーを指すことによって「互換性のある型」へのポインターを取得できないため、サブ構造へのポインターを安全に使用することはできません。例:後

struct Foo {
    short a;
    int b;
};

struct Bar {
    struct Foo foo;
};

struct Bar bar;

ポインター&bar.foo&bar.foo.aは異なる型を持ち、同じ意味で使用することはできません。また、厳密なエイリアシング規則に違反せずに互いの型にキャストすることもできず、未定義の動作がトリガーされます。

structこの問題は、毎回定義全体をインライン化することで回避できます。

struct Bar {
    struct { short a; int b; } foo;
};

Nowはと互換性のある型&bar.aへのポインタです。struct {short; int;}struct Foo

struct(また、型指定されたメンバーとプリミティブ メンバーの間にパディング/配置の違いがあるかもしれませんが、これらの例を見つけることができませんでした。

于 2013-11-04T11:45:06.583 に答える