LINUX.ORG.RU

c-oop-gen: ООП в Си

 , , , ,


1

1

Программирование в ООП-стиле на Си как правило порождает достаточно большое количество boiler plate кода. А итоговая программа пестрит приведениям типов. «Хватит это терпеть» решил я и запилил сие поделие: https://github.com/KivApple/c-oop-gen.

1) Вы описываете структуру классов (поля, методы, наследование) в XML-формате.

2) Вы генерируете два заголовочных файла из этого описания. Рекомендуется делать это не в ручную, а в качестве одного из шагов компиляции проекта.

3) Первый файл вы инклюдите всюду, где хотите использовать описанные классы. Второй файл вы инклюдите только в модуль с реализацией соответствующих классов (там описаны таблицы виртуальных методов).

4) PROFIT

Пример описания пакета классов:

<?xml version="1.0" encoding="utf-8" ?>
<package>
    <include file="stdlib.h"/>
    <class name="BaseObject">
        <method name="destroy" virtual="yes">
        </method>
    </class>
    <class name="DerivedObject" inherits="BaseObject">
        <field name="tmp" type="int"/>
        <method name="foo">
            <arg name="bar" type="int"/>
        </method>
        <method name="staticMethod" static="yes"/>
    </class>
</package>

После этого методы классов можно вызывать легко и просто:

DerivedObject_foo(another_object, 10);
DerivedObject_staticMethod();
DerivedObject_destory(another_object);
BaseObject_destroy(some_object);

Как можно заметить, при наследовании класса от другого, создаются обёртки для всех методов, которые не были переопределены, что позволяет отказаться от ручного приведения типов.

Поддерживаются виртуальные методы (как абстрактные, так и имеющие реализацию, к слову, переопределять в потомках можно только виртуальные методы), статические методы (не наследуются потомком, рекомендуется конструкторы делать на них) и обычные. Также любые методы могут получить переменное число аргументов с помощью атрибута «variadic».

Конструктор может быть любой функцией. Главное присвоить obj->vtable = &ClassName_vtable, если класс содержит хотя бы один виртуальный метод.

Деструкторы - это обычные виртуальные функции.

Разумеется, чудес не бывает и ответственность за вызов родительских реализаций методов (особенно актуально для конструкторов и деструкторов) лежит полностью на вас. С другой стороны это предоставляет и большую гибкость.

В отличии от многих других библиотек привносящих ООП в Си, сгенерированный код не требует НИЧЕГО (даже libc). Ведь это просто набор define'ов и структур.

Кстати, пакеты классов могут использовать друг-друга с помощью <include package=«some-package.xml»>. В этом случае можно будет наследоваться от классов объявленных в другом пакете (а сгенерированный исходник будет содержать #include «some-package.h»). При этом однако же генерировать заголовочный файл для подключенного пакета придётся отдельно.

Также должен более-менее нормально работать автокомплит в вашей любимой IDE (разумеется, только после генерации заголовочных файлов), потому что имена у функций получаются более-менее понятные.

В общем, такие дела. Покритикуйте какие ещё возможности стоит добавить, а что, возможно, я сделал не так. Сообщения о багах также приветствуются. Безусловно, данный проект можно написать достаточно быстро, но я не нашёл аналогичные проекты.

★★★★★

Есть же крутой Objective-C, где ООП наиболее гибкое, есть и православный последователь - Apple Swift. Рекомендую.

На крайняк, гомофобам рекомендую D - там легко обёртываются Cишные либы, функции и прочее.

menangen ★★★★★ ()
Ответ на: комментарий от menangen

Главный недостаток по сравнению с моим решением - требуется поддержка компилятора под целевую архитектуру + наличие рантайма.

Моё решение не требует вообще ничего. Его можно использовать даже там, где нет libc. Также оно должно скомпилиться большинством компиляторов Си (а Си, как известно, есть абсолютно везде).

Не думаю, что использование ObjC подойдёт для программирования какого-нибудь микроконтроллера. В то же время, например, та же ChibiOS/RT реализует некий ООП с виртуальными таблицами (разумеется, ценой кучи повторяющегося кода), так что потребность в больших проектах в этом таки бывает.

Понятное дело, что какой-нибудь C++ будет на порядок круче подобной утлиты, но она нужна для тех случаев, когда применение C++ нежелательно.

KivApple ★★★★★ ()
Ответ на: комментарий от anonymous

cfront заброшен, да и я не видел живых и более-менее функциональных проектов перевода С++ в С. Разве что бек-энд для llvm, но его выпилили в новых версиях.

KivApple ★★★★★ ()
Ответ на: комментарий от KivApple

cfront заброшен

Под «переоткроешь» я имел в виду «напишешь аналог».

я не видел живых и более-менее функциональных проектов перевода С++ в С

Ну вот, тебе будет чем заняться. Правда, с zero-cost исключениями будет сложно.

anonymous ()

ООП на Си

ООП не в синтаксисе, а в голове.

Вы описываете структуру классов (поля, методы, наследование) в XML-формате.

Спасибо, поблевал. Что угодно лучше ксымля, даже жейсон (щютка, жейсон тоже убог).

kawaii_neko ★★★★ ()
Ответ на: комментарий от RazrFalcon

И как из Rust сделать C? Он компилирует только с использованием LLVM. Бек-энд для LLVM, выдающий сишный код не поддерживается. К тому же лично я не знаю, насколько этот сишный код будет страшным (в смысле, насколько он полагается на то, что кучу лишнего кода потом заоптимизирует компилятор). В то же время под некоторые платформы существует только какой-нибудь SDCC, который, во-первых, умеет только Plain C, а, во-вторых, оптимизатор не очень крут.

KivApple ★★★★★ ()
Ответ на: комментарий от kawaii_neko

И в каком формате, ты считаешь, надо это хранить?

JSON ИМХО будет достаточно страшно смотреться на такой структуре данных.

Пока кроме XML мне видится вариант парсить очень ограниченное подмножество C++ (по сути дела только описания типов, причём без инлайнинга методов).

KivApple ★★★★★ ()
Ответ на: комментарий от hobbit

какой ещё концепт? это обычный кодогенератор наверняка даже без проверки корректности синтаксиса получившегося высера. такое умел даже бесм-1 в далёких 90х до нашей эты динозавров, тот который на релюхах был. тоже мне концепт

anonymous ()

автор, освой нормальный язык программирования созданый для твоих задач, ненадо рефлексировать и насиловать жуков.

anonymous ()
Ответ на: комментарий от KivApple

И в каком формате, ты считаешь, надо это хранить?

В человекочитаемом и человекоредактируемом, максимально похожем на C и расставляющем line-директивы.

Впрочем, для джаст-фо-фана все это не имеет значения, а для реального применения есть C++.

kawaii_neko ★★★★ ()
Ответ на: комментарий от menangen

Есть же крутой Objective-C, где ООП наиболее гибкое, есть и православный последователь - Apple Swift. Рекомендую.

в целом согласен, но разве для них уже есть хотя бы необходимый базовый минимум для кроссплатформенной разработки? компилятор последней версии objc вообще есть хотя бы под линукс?

2OP: ну и жесть ты придумал.. наверняка ты еще и не первый, что еще печальнее...

waker ★★★★★ ()

Ага, только недавно подобное добро, написанное в нулевых, из проекта выпилили.

code += "&%s_vtable, " % self.name
code += ", ".join(field.name if field.init is None else field.init for field in self.fields)
code += " }\n"
code += "\n"

Нет, у нас всё-таки до /такого/ не доходило.

GoodRiddance ()

О йее. Сишники же таак любят xml!!!

unt1tled ★★★★ ()

https://github.com/GNOME/vala

$ cat hello.vala 
public class Welcome : Object {

        string hello = "Hello, KivApple!";

        void println(string str) {
                stdout.printf ("%s\n", str);
        }

        public void run() {
                println(hello);
        }

        static int main(string[] args) {
                var welcome = new Welcome();
                welcome.run();
                return 0;
        }
}

$ valac -C hello.vala

$ cat hello.c | pastebinit 
http://paste.org.ru/?4s9am6

$ gcc hello.c -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -lgobject-2.0 -lglib-2.0

$ ./a.out 
Hello, KivApple!

EXL ★★★★★ ()
Ответ на: комментарий от KivApple

Я понимаю ваше решение и все эти заморочки с «контроллерами», но нужно смотреть на реальность. В реальности такие решения мало востребованны, программистам проще перейти на Swift, Go, D, чем бороться с отсутствием ООП в C. К тому же Objective-C вперемешку с Си, нормально компилируется под все платформы, в т.ч. и под win, я как-то писал Python модуль на objective-c, который компилился в .dll, и всё прекрасно работало. Но сейчас я ратую за Swift и D. То, что Swift рантайма нет под win - меня не напрягает, заказчики в основном хотят софт под UNIX. Сейчас я пилю проект на смеси Swift и C и часть кода (основное ядро) написано на С, а Swift как обёртка, но компилится это в shared object и executable, который эту библиотеку использует - и все довольны.

menangen ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.