LINUX.ORG.RU

Посоветуйте современную эмуляцию «классов» для С в эмбеды

 , ,


3

3

https://github.com/lvgl/lvgl/issues/1919

По ссылке я выписал основную литературу и библиотки. Там все толково, но не знаю насколько актуально.

Если кто в курсе, на чем нынче модно ООП для С изображать, дайте знать. Надо для эмбедов:

  • много оперативки жрать нельзя.
  • много флеша жрать не желательно.

По фичам критично только наследование методов/данных и virtual. Можно забить болт на private, эксепшены, множественое наследование и т.п.

Ответ типа «лучше ooc toolkit до сих пор ничего не придумали» - тоже устроит.

★★★★★

Готовое массово применяющееся решение: GObject.

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

вариант «не выёживаться» и использовать в базе С++ (как С с классами + stl) чем не устраивает ? вам модно-молодёжно или всё таки ехать ?

Разработчики молодые, вежливые, стесняются после опроса сказать тридцати процентам юзеров чтобы валили нахер :). Лично я бы сказал. Плюс биндинг к микропитону отвалится - тот кто делал, сказал что повторять подвиг еще раз не готов.

В общем, есть разные мнения, и за плюсы тоже топили на полном серьзе. Пока не дозрели. Но совсем без наследования тоже нельзя.

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

Про libcello не знал. Спасибо.

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

foo { a, b };
bar { c, d } : extends foo;

Вот хочется дергать bar.a & bar.b напрямую. Аналогично для методов в vmt.

Если вместо сишного «вкладывания» продублировать ручками - наверное будет постоянно ломаться. Знакомый предложит такой вариант:

#define FOO_PROPS \
  int a, \
  int b \

#define BAR_PROPS \
  FOO_PROPS, \
  int c, \
  int d

IMO как-то стремновато выглядит, хотя имеет право на жизнь.

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

Пишут, можно делать так (в gcc вам, возможно, потребуется поставить флаг «-std=c11» или «-fms-extensions»):

typedef struct bar 
{
  union
  {
    struct foo;
    struct foo base;
  };
  int c, d; 
} bar;
monk ★★★★★
()

Есть вот такая штука https://github.com/JuliaComputing/llvm-cbe - таким образом можно собрать что-то обычным clang++ в байткод LLVM, потом оттранслировать в C. Не знаю насколько это всё будет читаемым, нормально ли оно откомпилится какими-нибудь нестандартными эмбеддед-компиляторами, не будет ли там чего-нибудь лишнего и как потом это дебажить, но просто упомяну как вариант.

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

Не сразу вкурил. Очень похоже на то что хотел.

Большое спасибо!

Vit ★★★★★
() автор топика
Последнее исправление: Vit (всего исправлений: 1)
Ответ на: комментарий от alysnix

ниоткуда не следует, что преобразование к типу object в данном случае корректно

В данном случае это абсолютно корректно. Стандарт языка Си гарантирует это.

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

Когда у тебя немаленькую часть программы пишет препроцессор макросов, но при этом ты не участвуешь в соревновании по обфускации кода, это, скажем, не очень хорошо, и грабли обязательно вылезут! Ты можешь создавать типы данных типа словарей или списков (если именование через точку не важно, будет быстрее), нужен или динамический тип данных вроде вектора или просто сделай родительскую структуру членом дочерней (bar.parent.a вместо. bar.a). Нужно знать объем, занимаемый структурой в памяти, заранее (даже типы не так важны с явным приведением)

http://nlpc.stanford.edu/nleht/Science/reference/c_inheritance.pdf

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

Только к растовым трейтам это мало отношения имеет.

Если ты не изучал Rust, а лишь смотрел на синтаксис издали, то да.

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

Жду твоей реализации Rust trait object на С.

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

Если ты не изучал Rust, а лишь смотрел на синтаксис издали, то да.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&am...

Жду твоей реализации Rust trait object на С.

Нет, спасибо. Добавь, лучше, метод make в свой трейт и функцию test1.

korvin_ ★★★★★
()
Последнее исправление: korvin_ (всего исправлений: 1)
Ответ на: комментарий от korvin_

Добавь, лучше, метод make в свой трейт и функцию test1.

Добавил.

typedef struct {
    char const* error;
    Circle c;
} ResultCircle;

static bool IsErrorResultCircle(ResultCircle const* r)
{
    return r->error != NULL;
}

static ResultCircle MakeCircle(double const* initvals, size_t size)
{
    assert(initvals != NULL);
    ResultCircle result;
    if (size < 1) {
        result.error = "expected 1 initval at least";
    } else {
        result.error = NULL;
        result.c = (Circle){.radius=initvals[0]};
    }
    return result;
}

static void test1Circle (double initval) {
    double initvals[] = {initval};
    ResultCircle r = MakeCircle(initvals, sizeof(initvals)/sizeof(initvals[0]));
    if (IsErrorResultCircle(&r)) {
        printf("ERROR: %s\n", r.error);
    } else {
        printf("Area = %f\n", CircleArea(&r.c));
    }
}

Если хочешь можешь замакросить этот код, чтобы можно было сгенерировать для любых типов, а не только Circle. Это возможно сделать.

Но так и не понял, что ты хотел сказать. То что в С нету дженериков и паттерн матчинга? Так это я и так знал. Спасибо что напомнил.

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

bar.parent.a вместо. bar.a

Вот именно это бы и не хотелось. Ни для данных ни для методов.

Корявые макросы конечно не очень хорошо, но оно +/- локально, только при объявлении. А bar.parent.a по всему коду разлетится.

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

То что в С нету дженериков и паттерн матчинга?

Дженерики и паттерн-матчинг тут не при чём. Вот тебе без Result, раз он отвлёк твоё внимание: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&am...

Если хочешь можешь замакросить этот код, чтобы можно было сгенерировать для любых типов, а не только Circle. Это возможно сделать.

Так сделай. А пока что у тебя не растовые трейты, а гошные интерфейсы.

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

Слышал про приведение типов?

typedef struct {...} Foo;
typedef struct {
    Foo f;
    ...
} Bar; 

Bar *b = Bar(a, b);
...
Foo *foo = (Foo *) b;

Стандарт Си вроде как подразумевает нулевой отступ в памяти для первого элемента в коде структуры, поэтому явное приведение к другому типу здесь работает. Вместо методов используй колбэки с приведением типа к (void *)

mazdai ★★★
()

Используя unnamed structs и unnamed unions у меня получилось вот такая эмуляция C++: https://gcc.godbolt.org/z/b3YrTx

Там есть неприятные моменты, они помечены комментами.

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