Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет nancygold ([info]nancygold)
@ 2024-07-23 00:38:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Настроение: amused
Entry tags:computing

Quikest way to implement C++ style OOP in C99
Sometimes it is useful to pack functions and related data into some single struct.
Yet without language support it can be a bit tedious.
Here is a set of macros to do that easier than in C++.
To implement a template class, just put your class code inside the header, and then

#define CLASS
just before including it.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define NOOP_IMPLEMENTATION
#include "noop.h"


#define CLASS CObj

METHODS
  void (*foo)(int a);
  int (*bar)(int a);
  CObj *(*set_xy)(int nx, int ny);

BDATA
  int x;
  int y;
EDATA

METH(void,foo,int a)
  printf("foo a=%d x=%d y=%d\n", a, this.x, this.y);
  printf("self.bar returned %d\n", self.bar(a+3));

METH(int,bar,int a)
  printf("bar a=%d x=%d y=%d\n", a, this.x, this.y);
  return a * 2;

METH(CObj*,set_xy,int nx, int ny)
  this.x = nx;
  this.y = ny;
  return &this;

CTOR
  o->x = 123;
  o->y = 456;

END


int main(int argc, char **argv) {
  CObj *a = new(CObj);
  CObj *b = new(CObj);
  $(a).set_xy(111,333);
  printf("a...\n");
  $(b).foo(69);
  printf("b...\n");
  $(a).foo(7);
  return 0;
}

#ifndef NOOP_H
#define NOOP_H
extern void *gthis_;

#define new(type) type##_init(malloc(sizeof(type)))

#define $(o) ((gthis_=(o)), *((o)->vtbl_))
#define self $(this_)
#define this (*this_)

#define PRFX_(prfx,mid,name) prfx##mid##name
#define PRFX(prfx,mid,name) PRFX_(prfx,mid,name)

#define METHODS typedef struct CLASS CLASS; typedef struct {

#define BDATA } PRFX(CLASS,_,CVtbl); struct CLASS {CObj_CVtbl *vtbl_;
#define EDATA }; PRFX(CLASS,_,CVtbl) PRFX(CLASS,_,vtbl_); \
  void PRFX(CLASS,_,dummy_)() {

#define METH(type, name, ...) } \
  type PRFX(CLASS,_,name) (__VA_ARGS__); \
  __attribute__((constructor)) void PRFX(CLASS,__init__,name)() { \
    printf("initing %s\n", #name); \
    PRFX(CLASS,_,vtbl_).name = &PRFX(CLASS,_,name); \
  } \
  type PRFX(CLASS,_,name) (__VA_ARGS__) { CLASS *this_ = gthis_;


#define MINIT(name) PRFX(CLASS,_,vtbl_).name = PRFX(CLASS,_,name)
#define CTOR } CLASS *PRFX(CLASS,_,init)(CLASS *o) \
  { o->vtbl_ = &PRFX(CLASS,_,vtbl_);

#define END }




#ifdef NOOP_IMPLEMENTATION
void *gthis_;
#endif

#endif


(Добавить комментарий)


[info]nancygold
2024-07-23 00:45 (ссылка)
I'm sure with a bit of more advanced macro wizardry one cane make it even more usable.

(Ответить) (Ветвь дискуссии)


(Анонимно)
2024-07-23 01:14 (ссылка)
but why?

(Ответить) (Уровень выше)


[info]remedie
2024-07-23 03:31 (ссылка)
I believe I saw something like this in GTK+ (GObject framework? Can't remember). Choosing C over C++ matters for those who often compile entire systems from sources, as C++ compiler seems to be much slower. I never fully understood that, because you could actually refactor C++ code so that it takes less time to compile.

(Ответить) (Уровень выше) (Ветвь дискуссии)


(Анонимно)
2024-07-23 05:15 (ссылка)
glib programming is unpleasant. They also have the whole reflection framework called gobject-introspection. I don't understand this desire not to use more complex languages, with type systems specifically designed to work with this shit.

(Ответить) (Уровень выше)


[info]nancygold
2024-07-23 11:05 (ссылка)
GTK uses C, because C has stable ABI and more people know it.
I.e. it is easy to read macros, compared to templates.

I.e. you can just pass C's vtable struct around and everyone can easily expose it to their scripting languages.
Compare that to C++, whose vtable and rtti have no ABI.

(Ответить) (Уровень выше) (Ветвь дискуссии)


(Анонимно)
2024-07-24 01:19 (ссылка)
>Compare that to C++, whose vtable and rtti have no ABI.

Чо чо чо? Зачем ты непрерывно несешь бред? Вот ну постоянно, в каждом посте, в каждом втором комментарии.

https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components (это если что стандартный C++ ABI для x86 который используют и на линуксе и на маке)

(Ответить) (Уровень выше)


(Анонимно)
2024-07-24 03:30 (ссылка)
Кстати говорят, что в MSVC тоже теперь (с 2019ого) есть стабильный ABI (private one), и clang его имплементит.

(Ответить) (Уровень выше)


(Анонимно)
2024-07-23 02:53 (ссылка)
OOP is cancer.

(Ответить) (Ветвь дискуссии)


(Анонимно)
2024-07-23 06:35 (ссылка)
More like AIDS, no wonder Sadkov likes to spread it.

(Ответить) (Уровень выше)


[info]nancygold
2024-07-23 11:07 (ссылка)
OOP is useful for APIs and breaking program into modules.
I.e. it is an organizational thing.

It is also useful for implementing stuff like vectors and matrices.

OOP is bad for simulations or inheritance.
Here you need composition instead.

(Ответить) (Уровень выше) (Ветвь дискуссии)


(Анонимно)
2024-07-23 11:34 (ссылка)
Modules are not OOP.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]nancygold
2024-07-23 12:36 (ссылка)
As long as you have just a single instance of each module.

(Ответить) (Уровень выше)


(Анонимно)
2024-07-23 09:23 (ссылка)
Кстати решил таки прочитать что такое RISC OS. Обнаружил смешное:

"The OS is single-user and employs cooperative multitasking (CMT).[56] While most current desktop OSes use preemptive multitasking (PMT) and multithreading, RISC OS remains with a CMT system. By 2003, many users had called for the OS to migrate to PMT.[57] The OS memory protection is not comprehensive.[58][59]"

Т.е. infinite loop или deadlock вешает систему, а эквивалент sigsegv её крашит.

Но да, в 89ом это было неплохо в сравнении с досом: www.youtube.com/watch?v=QH-wu2gk1Is В особенности привлекательно, что всё шло комплектом с графическим и звуковым чипом, и было стандартным.

Но просрало в производительности интелю en.wikipedia.org/wiki/File:Archimedes_performance.svg

Тут говорят, что это вообще была singletasking os по сути:

"RISC OS is basically a one-thing-at-a-time OS. How we multitask is a matter of smoke and mirrors and not making assumptions (like expecting font, colour, or OS_GBPB position 1) to be the same between polls. Hell, one cannot reliably assume file handles are constant across polling (especially if something naughty did a *Close and a bunch of handles were reopened with one of them using the same handle you’re using)."

Не знал что исходники недавно открыли. Педия пишет, что какие-то древние версии тоже утекли на пайратбей.

(Ответить) (Ветвь дискуссии)


[info]nancygold
2024-07-23 11:09 (ссылка)
>It is too simple and doesn't even include telemetry and bloatware!!111

Okay.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Простота хуже воровства
(Анонимно)
2024-07-23 17:58 (ссылка)
More like "it was less reliable than the unixes of the era and, and only worked on hardware that was very expensive and slow, had no redeeming features over windows 3.1"

(Ответить) (Уровень выше)