Care.Card UX Contest: React Native + UX Design for better healthcare. Join Now & Win 100 000 SOLVE!
×Закрыть

С++ STL for embedded development

Є проект на плюсах 14-го стандарту під невеличкий пристрій, який доволі обмежений в своїх ресурсах,хочеться використати на ньому STL контейнери і, відповідно, алгоритми та ітератори до них.

Можливо, хтось може порадити готові ліби, дуже бажано під МІТ ліцензією, які надавали аналоги стандартних контейнерів.

Щось по типу ETL www.etlcpp.com конкретно ця не підійшла.

обмеження на розмір кінцевого бінарника 1 mb 400 kb

Дякую всім, зупинились на ідеї написання власних аналогів.

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

1. Всё-такие попробовать допилить напильником ЕТЛное.
2. Если никак не допиливается — взять какую-либо из портабельных существующих реализаций и откомбилировать с отключенными эксэпшэнами.
3. Если не нашлось — написать свои нужные контейнеры (не так уж сложно).

set(ARDUINO_C_FLAGS      " -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -fdce")
set(ARDUINO_CXX_FLAGS    "${ARDUINO_C_FLAGS} -felide-constructors -fno-threadsafe-statics -std=c++11")

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

А какой проект, в котором так легко заменить С на С++?

Любой...а переписывал либы ардуины чужие + свое сразу на ++ писал. С это прошлый день полюбому, ибо «trust in your compiler» и ++ сделает код не хуже, а писать легче.

Особенно для ядра)

Это историческое скорее, чем реальная необходимость сегодня. Как я понял, ядро соляриса на плюсах. Вот тут поболее тема www.linux.org.ru/forum/general/1526069

Не знаю, как там у них с ядром, а когда мне нужно было на соляре перегрузить глобальный operator new, компилер падал.

А in-place конструктор?

Пытался сделать циклический менеджер памяти, чтобы вся мелочь при обработке fcgi запроса быстрее выделялась/удалялась. Не получилось из-за компилера. Забил. in-place конструкторы отдельно не мучил. И вообще, это лет 5 назад было.

Как я понял, ядро соляриса на плюсах.

Исходники открыты, покажи.

У них есть компоненты на С++, но насколько нужно быть не в теме истории, чтобы сказать, что у классического юникса ядро на С++!

За что купил, за то и продал :) - ссылку дал, откуда взял. Исходники не смотрел, точнее, быстро нагуглил битые ссылки и забил.

Хоспади, за ссылки на ЛОР в приличном обществе экскоммуницируют.

А что тебе надо из STL? Мой опыт подсказывает мне, что чем ближе к embedded, тем чаще используют кастомные структуры вроде кольцевых буферов, ... которые не отражены в STL.

А вообще можно натаскать код из Linux Kernel как вариант...

А вообще можно натаскать код из Linux Kernel как вариант...

И заразить свой продукт GPL вирусом.

можно структуры и макросы переименовать

Чистить всё равно придётся — убрать всякие WRITE_ONCE, ... Скорее имеет смысл посмотреть на уже обкатанный рабочий интерфейс, особенно если собрались писать свои аналоги.

Розкажеш, що обрав, коли запуститься?

Порадились і вирішили писати своє, але трохи згодом, поки є більш нагальні задачі. Але ще продовжую шукати, якщо щось цікаве знайдеться — обовязково напишу.

Я ж и предлагал свое.. Правда очень ненастойчиво..

невеличкий пристрій

и

1 mb 400 kb

как то слабо умещаются.
У STL есть куча своих недостатков как и достоинств. Но вы уверены, что в вашем случае именно использование STL разгоняет размер бинарника?

Не бачу щоб тут хтось пропонував спробувати Rust (там нема ексепшенів), чи ви цих людей вже з’їли? :)

Ну стандартные вопросы возникают по поводу раста:
— а что мне это даст?
— а что делать с существующим кодом?
пока выгоды для мелких и средних — не видно. в больших конторах, решения принимает менеджмент — и там может произойти что угодно.

Тут уже готовый проект надо портировать dou.ua/...​rums/topic/24429/#1370771

обмеження на розмір кінцевого бінарника 1 mb 400 kb

Нифига себе народ разбалованный. И это невеличке устройство? Что за устройство? Может и в 32к влезть

Так мова ж не йде про те, аби скомпілювати Hello World і вкластись.
Окрім, власне, бібліотеки там ще буде написано куєву тучу бізнес-логіки, підключено інші необхідні ліби і т.д.

Либы ради либ? Ты сформулируй задачу. Если смогу, то есть что предложить. Туча бизнес-логики не пугает.

Задача формулюється доволі просто:
Знайти рішення яке б дозволяло використовувати стандартні STL контейнери з виключеними ексепшинами АБО знайти існуючий аналог STL контейнерів які б працювали без ексепшинів ну і коректно себе поводили там, де стандартні кидають, наприклад, bad_aloc.
Якось так, якщо дуже абстрактно.

Поменять аллокаторы уже советовали?

P.S. И какая же логика будет для bad_alloc?

Як варіант, якщо не вдалося виділити необхідний розмір, алокатор вертає nullptr і далі вже контейнер, яки його викликав обробляє цей результат, бо стандартний вектор очікує, що або пам’ять буде виділена і відпрацює конструктор або буде ексепшн.

Якщо обробляти усюди те, що повертає new, то коду буде стільки ж, як і з ексепшнами, лишень весь той код руками писати будеш.

Фу, убери за собой

Null куда? В глубь сторонней библиотеки?

Ну может я не понял, мне показалось там 3rd party есть

Энивей, вопрос как предполагается обрабатывать нехватку памяти остается открытым

крешиться — самый простой вариант

Тю, никакой фантазии

Энивей, вопрос как предполагается обрабатывать нехватку памяти остается открытым

А зачем её обрабатывать под линуксом? :)

иф нул — хьюстон, у нас проблемы

використовувати стандартні STL контейнери

STL контейнери є в STL

чому не взяти, як я писав POCO або Qt та використовувати їх структури даних,
ще як варіант, взяти Redis та працювати з ним як з контейнером даних

Проект вже існує, переписувати під Qt не варіант, щодо РОСО не впевнений, треба дослідити і поміряти.

Проект вже існує, переписувати під Qt не варіант

крива рахітектура

gcc вроде пишет, что STL должен компилиться с -fno-exceptions
gcc.gnu.org/...​ual/using_exceptions.html
Вариант, который я сейчас использую: для больших кусков/массивов выделяешь через mmap и проверяешь результат. Остальное выделяется через new, но этого остального не столько, чтобы незаметно выесть всю память, поэтому результат выделения не проверяешь.

STL контейнер это метод. А задача как стоит?

1 метр бинарника? Юзай обычный gcc-шный, только сборку возьми нормальную (либо сделай сам) --- большая часть сборок gcc идет с неоптимизированной стандартной библиотекой, а потом начинаются разговоры о жирном C++

Вы вообще в курсе, что libsupc++ --- часть gcc стандартной библиотеки?

Я конечно понимаю, что если собрать libsupc++ вручную, то народу проще прописать банальное -Os. Но проблема лишь в том, что сборщики кросскомпиляторов не смогли дать CFLAGS_FOR_TARGET и CXXFLAGS_FOR_TARGET при сборке, а потом удивляются почему стандартная библиотека у них вышла такая жирная

andriidevel.blogspot.com/...​xception-handling-on.html

А насколько исключения увеличивают сам код программы из-за дополнительных путей выполнения?

дополнительных путей выполнения

Дополнительных по отношению к чему? Программа либо обрабатывает ошибки, либо не обрабатывает ошибки. Очевидно, что программа, которая не обрабатывает ошибки будет занимать меньше места, чем та, которая обрабатывает

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

Ну а на сях будет что-то типа такого:

SomeClass* some_class_alloc(char *x, char *y, char *z, SomeOtherClass *obj)
{
    SomeClass *result = malloc(sizeof(SomeClass));
    if (!result)
        goto cleanup0;

    result->x = strdup(x);
    if (!result->x)
        goto cleanup1;

    result->y = strdup(y);
    if (!result->y)
        goto cleanup2;

    result->z = strdup(z);
    if (!result->z)
        goto cleanup3;

    result->sub_obj = some_other_class_foo(obj);
    if (result->sub_obj->bar != 10)
        goto cleanup4;

    return result4;

cleanup4:
    some_foo_free(result->sub_obj);
    free(result->z);

cleanup3:
    free(result->y);

cleanup2:
    free(result->x);

cleanup1:
    free(result);

cleanup0:
    return NULL;
}

Просто проверка ошибок очень сильно раздувает код, от этого не уйти

Ну вот вопрос, насколько прога с клинапами из-за поддержки исключений длиннее варианта без проверок?

У тебя мемлик в коде!

Почему не уйти? Я с этим борюсь двумя своими велосипедами. Во-первых, нечто вроде

void multialloc(size_t n, const size_t * sizes, void * restrict * ptrs, size_t granularity)

Который сразу одним махом выделяет память под всё (плюс выравние как дополнительная фишка).

Во-вторых это ипользование пула

struct mempool * create_mempool(size_t initial_size);
void free_mempool(struct mempool * restrict me);
void * mempool_alloc(struct mempool * restrict me, size_t size);
void mempool_align(struct mempool * restrict me, size_t bound);

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

Вы вообще в курсе, что libsupc++ --- часть gcc стандартной библиотеки?

Бугага! Это костылище, потому что gcc перестал нормально воспринимать -fno-exceptions -fno-rtti и всё равно генерирует обращения в стандартную библиотеку. Нах такие костыли.

Это костылище, потому что gcc перестал нормально воспринимать -fno-exceptions -fno-rtti и всё равно генерирует обращения в стандартную библиотеку.

Нет, не перестал. libsupc++ нужен для тех кому нужны эксепешены, но не хочет юзать built-in стандартную библиотеку. Это не более чем ABI support.

Вы еще откройте для себя libgcc

Нет, не перестал.

Перестал:

root@mikenfs:/usr/lib/x86_64-linux-gnu/dri# ldd i965_dri.so
linux-vdso.so.1 => (0×00007ffd983f7000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0×00007ffaabd09000)
libglapi.so.0 => /usr/lib/x86_64-linux-gnu/libglapi.so.0 (0×00007ffaabad9000)
libdrm_intel.so.1 => /usr/lib/x86_64-linux-gnu/libdrm_intel.so.1 (0×00007ffaab8b5000)
libdrm_nouveau.so.2 => /usr/lib/x86_64-linux-gnu/libdrm_nouveau.so.2 (0×00007ffaab6ad000)
libdrm_radeon.so.1 => /usr/lib/x86_64-linux-gnu/libdrm_radeon.so.1 (0×00007ffaab4a1000)
libdrm.so.2 => /usr/lib/x86_64-linux-gnu/libdrm.so.2 (0×00007ffaab290000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0×00007ffaab067000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0×00007ffaaae4a000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0×00007ffaaac46000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0×00007ffaaa8c4000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0×00007ffaaa5bb000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0×00007ffaaa1f1000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0×00007ffaa9fdb000)
libpciaccess.so.0 => /usr/lib/x86_64-linux-gnu/libpciaccess.so.0 (0×00007ffaa9dd1000)
/lib64/ld-linux-x86-64.so.2 (0×00007ffaaca0a000)

Он там не нужен, но по другому ты хрен соберешь.

Он там не нужен

Почему не нужен, там же код на плюсах

Потому что там С с классами и темплейтами, он там не нужен. После gcc3 с определенной версии они без стандартной библиотеки уже не могут, от неё не избавиться. Поэтому и ввели костыли.

Там виртуальные функции как минимум есть. И чисто виртуальные классы. Может вам стоит код месы поревьювить?

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

POCO, Qt

але напоркуа С++ в

пристрій, який доволі обмежений в своїх ресурсах
доволі обмежений

у каждого свое

тоді питання скорочується до

напоркуа С++

Строки, списки, локи — з ними набагато простіше працювати в С++.

в чім складність?
локи.... хз... помоєму треди появилися аж в 14++

Ось лок списка від інших потоків, перевірка того, що в ньому нема даного запису та додавання запису в список:

		{
			MutexLock	lock(mutex_);
			ASSERT(!callids_.In(call));
			ASSERT(!callids_.In(pjscallid));
			callids_.Add(call, pjscallid, line);
		}

Напиши те саме на С. Скільки тексту буде?

pthread_mutex_lock(&mutex);
LIST_FOREACH(np, &head, entries) {
    if ((np->field1 == call)  || (np->field2 == pjscallid)) {
        ASSERT(...);
    }
}
LIST_INSERT_HEAD(&head, line, entries);
pthread_mutex_unlock(&mutex);

Там перед инсертом еще будет выделение ноды и заполнение полей.

На С++ компактнее и не хуже читается

Наведи код джави. С та С++ вже є — порівняємо)

При использовании BSD queues ноды обычно не выделяют, а в структуру с данными вставляют BSD queue макро тип, что позволяет заранее выделенные структуры использовать в различных контейнерах.

Там просто добавление данных о хендлах звонка в приложении и в библиотеке в мапу-переводчик, чтобы в колбеке от библиотеки знать хендл для приложения, и наоборот. Больше нигде эта пара не выделяется, call приходит аргументом функции, pjscallid выделяется фреймворком. line — это ид SIP учетки, по которой звонок идет, иногда он тоже нужен.

Работа со стоками:

	case ACT_OUTGOING:
		if(line_name_) {
			ASSERT(dst_name_);
			result += "Line ";
			result += line_name_;
			result += ": outgoing call from HS ";
		} else
			result += "Outgoing call from HS ";

		result += src_name_;

		if(dst_name_) {
			result += " to ";
			result += dst_name_;
			if(number_matched_ == NM_MATCHED) {
				ASSERT(cnip_);
				result += " (";
				result += cnip_;
				result += ")";
			}
		}
		break;

для цього тре С++ бо в С строк нема

Аналог asprintfcat() пишеться на 20 строк за 10 минут, который так же грязно фрагментирует память как и С++ собрат.

Его вызовы вширь будут куда больше, чем += в плюсах.
Ну и у меня, к примеру, самописная строка фиксированной длины и лежит на стеке.

Ну если фиксированного размера, то ещё проще, но да, вширь будет немного длинее.

Чтобы зарабатывать деньги. Вначале за деньги заказчика создаются трудности, потом они решаются %) Все при деле!

Платный: www.dinkumware.com

А вообще переписать. Если в коллекциях не примитивные типы, то использовать BSD rbtree, BSD queues, даже в сложных вещах типа OpenGL драйверов это всё выкидывалось и переписывалось за месяц одним человеком.

Ми своє писали.
Які основні лімітації платформи? Чому не підходять STL, ETL, самописне?

Є дві причини, чому не підходить STL:
1) Хочеться відійти від ексепшинів ( головна причина)
2) Розмір кінцевого образу та швидкодія.

Схиляюсь до того, що таки доведеться своє писати.

2) Розмір кінцевого образу та швидкодія.

Темплейты и маленький размер бинарника are mutually exclusive :)

Ну в мене обмеження на розмір бінарника 1 mb 400 kb, теоретично, можна вкластись.

ні, все не настільки погано)

Неасилятор детектед

Неасилятор чего? Это законы вселенной.

Отличная отмазка!

Обвинил меня хз в чём, причём даже не уточнил, а теперь выясняется что я ещё и пытаюсь отмазываться! Вот это холивор!

Тут теж причиною був розмір (кажуть, коли відійшли від STL, зрізали близько метру на системі управління роутером) та ексепшни (котрі якось в них все валили). В результаті народ написав щось своє страшне, коли треба було робить телефонію — я на те подивився, злякався, й написав своє.
Мені зараз достатньо (проекту 4 роки, Actors):
Контейнери:
1) Фіксована строка (темплейт за розміром, інстанси довжиною 20, 100, 256, 512)
2) Двонаправлений список, варіанти: список за значенням, за вказівником з володінням та без володіння об’єктом
3) Інтрузивний список як базовий клас
4) Список масивів з доступом за індексом елемента
5) Кеш (індексна таблиця фіксованого розміру чи_заповнений:значення)
6) Словник фіксованого розміру на базі масива
7) Черга по значенню та по вказівнику
8) Сет на базі списка
9) Бітмаска
10) Lock-free ring buffer
Пам’ять:
1) Авто пойнтер звичайний
2) Авто пойнтер для масивів
3) Авто пойнтери для memmap
4) Thread unsequre reference counting smart pointer
Інше:
1) Id як базовий клас
2) Кілька функторів (байндерів) з алгоритмів, але вони не прижилися
3) Робота з типом символа, перевод ASCII/UTF8/KOI8
4) Ніббли
5) Оверлоад системних функцій роботи з мютексами
6) Таймер (в деструкторі друкує, скільки він жив)
7) Логгер (stderr/syslog/file)
Потоки:
1) Атоміки (gcc)
2) Мютекс
3) CondVar
4) Mutex+CondVar в одному класі
5) Lock (захоплення мютекса для секції кода)
6) sleep
7) time
8) Потоки
9) MessageHandler похідний від потока
10) Message
11) Таймера з власним потоком
IPC:
1) Клас, що запускає програму з купою пар name=value в environment
2) Сокети
Ще:
1) Вочдог для потоків
2) Обгортка над libusb
3) Парсілка конфіга (типу: a.b[c] = value) на макросах
4) CLI
5) Базові класи для запису та читання бази даних в файл
6) Бенчмарк (загружаємо N потоків пріоритета K, порівнюємо продуктивність з результатом до старта головного кода, отримуємо наскільки головний код грузить систему)
7) База даних, записи й індекси в пам’яті
8) Міні-регексп нестандартного синтаксису з фіксованим розміром вхідного тексту

1) Хочеться відійти від ексепшинів ( головна причина)

Зачем, лол?

из кьюта повыдирать? там эксепшенов нет

Подписаться на комментарии