Как стать автором
Обновить

Комментарии 35

Хотел бы, чтобы весь си++ был бы реализован как макросы над этим.

Сам стараюсь писать похожим образом.
Вообще есть objective-c.
Вот только я еще никого не видел, кто использует возможности языка как дополнение к си (без gnustep)
Ведь именно так и было в начале. Просто язык настолько разросся, что легче и эффективнее было написать компилятор напрямую.
Я бы добавил тег ненормальное программирование, а так вполне себе нормально!
А что тут ненормального? Даже в ядре linux такое используется в драйверах ФС, например.
Ядро линукс, драйверы, даже некоторые части игр (например рендер) — это системное программирование, оно отличается от прикладного. Для прикладного программирования придуманы кучи патернов, чтобы огромная армия программистов не отстреливала себе ноги. В системном свои правила, и основное — выжать максимум. Выжимается максимум явно нарушая правила прикладного программирования. Вот для обычных программистов то что в этой статье это ненормальное программирование. Для системого программирования это нормально!
Собственно это я и хотел выразить своим предыдущим посланием.
Я это послание понял, но разве сейчас используется C в «прикладном» программировании, где не важна скорость, тем более людьми, не знающими о возможности выстрелить во все части тела?
Почему нет? Я под линуксом пишу для GTK именно на нем. Конечно не глобальные проекты, от 500 до 4000 строк. Но лично для себя не вижу пока необходимости перелазить на что-то другое.
В исходниках Quake2 подобных виртуальных функций было полно. В общем-то в C++ обычно делается отдельно таблица функций, а в объекте хранится только указатель на таблицу для экономии памяти.
О glib и linux уже сказали.
В Go наследование тоже аналогичным образом делается.
А всё потому, что ООП — это, прежде всего, не синтаксический сахар, а парадигма. Почти на любом языке можно писать и в объектно-ориентированном стиле, и в функциональном, и в процедурном. Неудивительно, что элементы ООП встречаются во многих крупных проектах даже на тех языках, в которых нет специальных средств для ООП.
Баян, но всё же: libcello — виртуальные функции, конструкторы/деструкторы, замыкания, исключения. Всё чисто на макросах сишечки и паре расширений gcc.
Выглядит здорово. А о каких конкретно расширениях речь? (и поддерживаются ли они в clang?)
Насколько я понял, это всякие вложенные функции. Для Clang там реализация лямбд на родных кланговских блоках.
Спасибо.
Посмотрите glib. Вот уж где действительно ООП на C.
Только вот GObject в линуксовом сообществе многие недолюбливают. Почему — не в курсе, не было опыта использования.
Вы забыли «virtual» в самом первом примере кода на C++, — все три метода класса compressor должны быть виртуальными, иначе это не будет работать как вы написали.
Спасибо, поправил.
я бы использовал как-то так:
archiver_init(&arch);
archiver_work(&arch, ARCHIVER_ZIP, file );
archiver_destroy(&arch);
 

определил бы ARCHIVER_ZIP, ARCHIVER_BZ2, ARCHIVER_RAR как константы, и сделал бы вызовы на кэллбеках.
Хочу посоветовать книгу 21st Century C. В ней очень хорошо описываются все современные приемы.
скачал — спасибо
Вот очень интересная дискуссия на тему того, почему код написанный на D может быть более эффективным чем код скомпилированный на чистом С forum.dlang.org/thread/l7tij3$v6m$1@digitalmars.com

Хабр криво парсит ссылку, так, что лучше ее копировать в адресную строку.
Спасибо большое за статью, побольше бы таких статей!!!
1. указатели на функции можно было бы завернуть в табличку виртуальных функций, чтобы было как на си++. Либо сделать как в Go/Rust и создавать интерфейсы с указателем на данные + указателем на табличку виртуальных функций.
2. не понял зачем union в наследовании «a pointer to a structure is automatically converted to a pointer to an anonymous field for assignments and function calls» gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html
Union затем, чтобы можно было обращаться к базовому объекту по имени для передачи в код, ожидающий объект базового типа, т.е. для полиморфного использования в существующем коде и также чтобы возможно использовать данные базового объекта напрямую. В статье об этом есть.
>Union затем, чтобы можно было обращаться к базовому объекту по имени для передачи в код, ожидающий объект базового типа

«a pointer to a structure is automatically converted to a pointer to an anonymous field for assignments and function calls»

там даже пример есть в документации.
Да, вы правы, похоже сейчас это стало возможным без `union`, по крайней мере компилируется, работоспособность не проверял. Только компилировать нужно с другим флагом: `-fplan9-extensions`. Спасибо.
Порекомендую воздерживаться от макросов, которые неявно объявляют переменные в коде. Лучше воспользоваться например такой формой:

#define PREPARE_IMPL© \
({ \
assert©; \
assert(c->impl_); \
(rar_impl_t*)c->impl_; \
})



rar_impl_t *impl = PREPARE_IMPL©;
Если я не ошибаюсь, для этого требуются расширения от GNU. Я думаю, можно писать так:
#define PREPARE_IMPL(c) \
  (assert(c), assert((c)->impl_), (rar_impl_t*)((c)->impl_))

rar_impl_t *impl = PREPARE_IMPL(c);
Список «что я хочу от Си» можно дополнить возможностью перегружать обычные функции. В Си этого нет, к сожалению. Нельзя давать функциям одинаковые имена. Код
int add2(int ar) { return ar+2;}; float add2(float ar) { return ar+2.0;};
не компилируется компиляторами чистого Си, например TinyCC. Можно писать без классов и шаблонов и думать, что они пишешь на чистом Си. И компиляторы C++ поддерживают в этом заблуждении. Когда же берёшь шустрый в компиляции TinyCC, то тут открываются глаза.

Из компиляторов Си вроде бы только LCC поддерживает перегрузку функций. Но это расширение, не соответствующее стандарту.
Думаю, перегрузки никогда не будет в C, т.к. это требует манглинга имён, что автоматически ломает обратную совместимость и прозрачность работы компилятора и линковщика. К примеру, неясно будет, что нужно передавать в dlsym.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории