Решение загадки круговой зависимости «элегантно»

Поэтому я разрабатываю язык программирования, который компилируется в байт-код для исполнения виртуальной машины, а также в C как промежуточный язык для компиляции в нативный двоичный код. Я выбрал C, потому что он достаточно низкоуровневый и переносимый, что экономит огромное количество усилий за счет повторного использования существующих компиляторов и не требует написания компиляторов для сборки для каждой отдельной платформы и ее странностей.

Но существующие компиляторы имеют свои недостатки, одним из которых является проблема циклической зависимости. Я хочу решить циклические зависимости элегантным способом (в отличие от 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 ++ трудностей с круговыми зависимостями, а не логическим парадоксом «курица или яйцо». Очевидно, что два объекта не могут содержать друг друга, не приводя к некоторой форме бесконечного цикла.

4

Решение

Вы не можете безопасно использовать указатели на подструктуры, потому что вы не можете получить указатели на «совместимые типы», указывая на примитивные члены. Например. после

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

Сейчас &bar.a это указатель на struct {short; int;} который является совместимым типом для struct Foo,

(Там также могут быть различия между отступами / выравниванием structчлены и примитивные члены, но я не смог найти пример этого.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector