LINUX.ORG.RU

#embed принят в C23

 ,


0

2

https://thephd.dev/finally-embed-in-c23

Truly, a struggle.

It’s deeply depressing and ultimately a great source of burnout being at the grindstone for 4 years for things people were casually discussing about in September of 1995 (and earlier). It’s almost as depressing as putting typeof in the C Standard and then realizing this was something they’d been discussing doing since after C89 (1989). Am I destined to just keep closing the loop on old, unrealized dreams because a bunch of people were too tired/scared/busy/combative to standardize what has literally been decades of existing practice?

It was hard to realize how tired I was of this kind of grind until the day the feature was put into the C Standard, this past Tuesday. I quite literally could not even muster a “yes!” after the vote finished. I just felt empty and numb, because quite literally dragging an entire community of implementers through several hurdles, to finally get them to acknowledge the existence of a problem and its solution, is just… soul-crushing. It is a level of effort that I recommend to nobody in any sphere of life, for any task. At least when you are on the ground and organizing and helping people, you’re providing some kind of material value. Water. Food. Improving something. Here? I’m talking about things that are quite literally older than I am. Just trying to bring ideas from the last 3 decades - things you would think were Table Stakes for foundational languages like C and C++ languages - would not be seen as a radical new paradigm or shift in the language. Nevertheless, I spent (burned?) that energy, and finally.

It was all worth it.

Or. That’s what I keep telling myself. Because it doesn’t feel like it was worth it. It feels like I wasted a lot of my life achieving something so ridiculously basic that it’s almost laughable. How utterly worthless I must consider myself, that hearing someone complain about putting data in C++ 5 years ago put me on the track to decide to try to put something in a programming language standard. That I had to fight this hard for table scraps off the Great C Standard’s table.

What a life, huh?

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

★★★★★

Последнее исправление: fsb4000 (всего исправлений: 1)

Норм. Хотя до использования на практике этого ещё очень далеко, ведь всякие неизбежные #ifndef C23 #include «bin_to_hex_converted.inc» (для совместимости с не совсем новыми компиляторами) сводят на нет всю пользу.

И для инклюда не 8-битных массивов придётся ещё #define делать для конвертации рядом.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

Ну ок. Но один хрен ещё долгие годы все будут использовать свои варианты подобного. А именно просто трансилировать бинарники в сишный файл и инклюдить его или просто в hex трансировать и инклюдить.

inc.h

0xf,0xff,0xfff,

main.c

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

int main(int argc, char *argv[])
{
 int array[] = { 
    #include "inc.h"
};

for (int i = 0; i < 3; ++i)
{
    printf("%d\n",array[i]);
}
    return 0;
}
dron@gnu:~/Рабочий-стол/tt.c$ ./a.out 
15
255
4095
dron@gnu:~/Рабочий-стол/tt.c$ 

Вот тебе и #embed Конечно им удобнее будет вшивать бинари, но..

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от ox55ff

Можно будет сделать так


uint8_t array[] = 
{ 
    #embed  "maya_fotka_v_trusah.jpg"
}

image_draw(array);

Не нужно будет делать

     FILE * fopen("maya_fotka_v_trusah.jpg","r");
     if(file)
     {
        fseek(file,0,SEEK_END);
        long len = ftell(file);
        fseek(file,0,SEEK_SET);
        char * array = malloc(len);
        if(array){
           fread(string,len,1,file);
           image_draw(array);
        }else{
          ....
        }
     }

Конфиги вшивать в программу на этапе компиляции, всякую мелочёвку вроде иконок, шрифтов и чего то ещё по умолчанию которые.

Или просто делать игру в виде одного блоба. Можно зависимости в виде so библиотек вшивать в один бинарь, а при запуске выплёвывать их рядом и дёргать. Можно собрать программу которая при сборке запишет в себя свои исходники =) Короче нужно это что-бы где то что-то оптимизировать по доступу к данным или для какой иной мелочи. Такое себе.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU
#if defined(__MINGW32__) || defined(__MINGW64__)
#    define VAL_TYPE(S)
#    define VAL_NAME(S) _ ## S
#else
#    define VAL_TYPE(S) .type S, @object
#    define VAL_NAME(S) S
#endif

/* Для ARM нужно заменить @ на # */

.section .rodata
      .global VAL_NAME(del_query_commanddone)
      VAL_TYPE(del_query_commanddone)
      .align  4
VAL_NAME(del_query_commanddone):
     .incbin "./projects/infrastructure/dirty/delivery/code//query/del_query_commanddone.sql"
    .byte 0
VAL_NAME(del_query_commanddone_end):
     .global VAL_NAME(del_query_commanddone_size)
     VAL_TYPE(del_query_commanddone_size)
     .align  4
VAL_NAME(del_query_commanddone_size):
     .int    VAL_NAME(del_query_commanddone_end) - VAL_NAME(del_query_commanddone)
#ifndef DEL_QUERY_COMMANDDONE
#define DEL_QUERY_COMMANDDONE

#define EXPORT_FROM
#define EXPORT_TO

EXPORT_FROM
extern const char del_query_commanddone[];
extern const u32 del_query_commanddone_size;
EXPORT_TO

#endif /* DEL_QUERY_COMMANDDONE */
PPP328 ★★★★★
()
Ответ на: комментарий от PPP328

Линкером делаешь объектник:

ld -r -b binary -o schema_json.o schema.json

Допиливаешь напильником:

objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents schema_json.o schema_json.o

Далее пользуешься в коде:

extern const char _binary_schema_json_start;
extern const char _binary_schema_json_end;

std::string config::get_schema_string()
{
	size_t json_schema_size =
	    &_binary_schema_json_end - &_binary_schema_json_start;
	return std::string( &_binary_schema_json_start, json_schema_size );
}

Ищется легко, например https://stackoverflow.com/questions/4158900/embedding-resources-in-executable-using-gcc

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

В статье описываются проблемы такого подхода.

Можно цитату? Не нашёл такого. Самое близкое «Every compiler, every linker, every platform had its own little bespoke way of sticking data into your executable.», но #include не зависит ни от линковщика ни от платформы и вообще в стандарте.

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

И для инклюда не 8-битных массивов придётся ещё #define делать для конвертации рядом.

Они уже предложили расширения делать в стиле

#embed </dev/urandom> limit(2+2) sdcc::element_type(int32_t)
monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

И какие? Неизветен размер данных? Ну так можно не просто hex через запятую засунуть, а целую структуру с длинной и всем чем надо. Зато это будет работать на любой сишке даже начиная от суперкомпьютеров заканчивая микроконтроллерами для полива теплиц. А суть то одна и та же. Единственный минус нужно предварительно преобразовать бинарные файлы в нужный вид, но на уровне сборки кода это плюс одна команда конвертора который пишется на коленке за 2 минуты. Всего то нужно открыть файл читать побайтово и записывать в другой файл hex значения. Повторюсь единственный плюс #embed это избавление от вот этой подготовки, ну и всё =)

Я вот у себя беру файлы игры конвертирую их в стурктуры. Затем их всех я собираю в so библиотеку и затем в игре если мне нужен файл я делаю запрос просто по имени файла, сначала попытка загрузить просто с файловой системы, если нету по имени файла берётся структура с данными из so библиотеки, так же удобно на лету менять ресурсы просто подсовывая другую либу с ресурсами. В случае чего можно скомпилировать в обектник и слинковать статически. Вот если я буду использовать #embed едиснтвенный плюс для меня будет в том что вместо генерирования файлов для компиляции ресурсов в блоб, я буду генерировать файлы для компиляции ресурсов в блоб чуть по другому. Один хрен генерировать придётся.

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

Да, удобно. Да, прикольно. Да такое вообще 40 лет назад надо было сделать. Но то что оно появится так поздно окупится лет через 10. Когда уже будет писать на чём то выше c11 и это будет ок. А пока, а пока есть уже рабочая альтенратива с тупым include разве что надо фалы подготавливать, ну хоть не руками.

Я за #embed фичу , но пользоваться ею не буду. Ка и я за дженерики в c11 обоими руками, но пользоваться ими не пользуюсь. А порою они могли бы так сильно упростить жизнь. Но они упрощают в каком то одном месте где они хорошо заходят, а потом смотришь что ты себе принёс не просто фичу, а целый новый язык и такой нунафиг.

Этой фичей будут пользоваться наши внуки, им будет хорошо, всё для детей =)

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от monk

#embed </dev/urandom> limit(2+2) sdcc::element_type(int32_t)

Это::что::за::с++::в::сишке!!!! Нипазволю! Нинада! А то я форкну сишку от с89 до с24draw выкину всё плохое осталю всё хорошее выкину всё плохое из хорошего и у меня получится ОДныН! Яязык под всё, я зохвачу плонету и все начиная с дестского садика учить адресную арифметику ещё до азбуки! Я в ней сам путаюсь поэтому будет нужна помощь молодежи гыгы

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

Конфиги вшивать в программу на этапе компиляции, всякую мелочёвку вроде иконок, шрифтов и чего то ещё по умолчанию которые.

Это все и щас нетрудно сделать :)

Или просто делать игру в виде одного блоба.

чо не сделают лишь бы дамп из выхлопа xdd или... hexdump не копипастить... вот жопы ленивые :)

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

Толь не знал толь забыл, но у меня считай тоже самое делается. Я кажется как-то тут тему про это создавал даже. А так да всё изобретено до нас и давно уже готово, тока не всегда додумываюсь в эту сторону искать, а стоит ибо консольных утилит на все случаи жизни херова гора. =) Но у меня болезнь головной извилины ибо прежде чем подумать я лезу лесапедировать свой велосипед, а когда в большиснтве случаев (но не во всех!) у меня ничего не получается ибо я баран я иду уже искать что-то готовое ыгыг

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)

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

Он пишет о том, что включили что-то, что явно вообще не очень то и нужно. Мелочь, пустяк, но она очень дорогая в плане того, что каждая строчка в стандарте - это человеческое время на чтение, согласование и имплементацию.

Каждая новая строка в стандарте должна быть согласована со всеми предыдущими, а значит что-то важное и полезное надо будет согласовывать с этим embed.

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

чо не сделают лишь бы дамп из выхлопа xdd или… hexdump не копипастить… вот жопы ленивые :)

там в этой статье он замеры приводил(давая ссылку на свою старую статью https://thephd.dev/embed-the-details), когда убеждал в нужности #embed

                      40 мегабайт данных
gcc #embed            1.069 s
objcopy (linker)      2.183 s
xxd-generated         225.290 s
                      1 гигабайт данных
gcc #embed            11.887 s
objcopy (linker)      58.204 s
xxd-generated         OoM 😝

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

fsb4000 ★★★★★
() автор топика
Последнее исправление: fsb4000 (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

Вот именно потому что по сей день всяк на свой лад велосипедирует подобные костыли, множит вопросы на stackoverflow, пишет очередной bin2hex — #embed вещь нужная и актуальная.

Впрочем, среди костылей давным–давно существует стандартизированное, MISRA-совместимое, протестированное на куче компиляторов решение. Удивлён, что оно до сих пор не упомянуто в топике. Исправляю положение:

https://github.com/graphitemaster/incbin

Работает через инлайновый ассебмлер и incbin, подобно решению из этого сообщения, но с кучей логики на условных макросах для учёта особенностей разных компиляторов, в т.ч. msvc.

Quote
()
Ответ на: комментарий от olelookoe

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

И шансы на то, что починят падение на крупных файлах (gcc, tcc) или ошибку «error: sorry, unsupported: file ‘test.c’ is too large for Clang to process» для clang стремительно падают.

monk ★★★★★
()

Or having to reaffirm that no, you can’t just “Use a String Literal”, because MSVC has an arbitrarily tiny limit of string literals in its compiler (64 kB, no they can’t raise it because ABI, I know, I checked with multiple bug reports and with the implementers themselves as have many other frustrated developers).

Нашёл в статье ошибку.

В VS 2022 убрали ограничение на максимальную длину строкового литерала. Теперь ограничением на длину является лишь объём памяти. И забыли обновить доки.

https://imgur.com/a/u5mpa6G

Создал PR: https://github.com/MicrosoftDocs/cpp-docs/pull/4063

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

«And in another comment, I alleged that #embed is garbage unless optimized.» (C)

Что ни сделают, жопы ленивые, лишь бы делать комбайны из всего, а не оптимизировать xxd или линкер ))

Особенно смешны эти замеры, будто эти дампы нужно генерить каждый раз.

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

ибо есть теперь решение стандартное, ура

которое или будет зоопарком реализаций со своими трейд-оффами, или будет... не слишком распространено в продакшене, т.к. компиляторы там традиционно отстают. Т.е. «революция» как обычно станет еще одним конкурирующим за ресурсы живтоне в зоопарке, а там и xxd подтянется, или выйдет исследование почему практика расходится с «бенчмарками» :)))

slackwarrior ★★★★★
()

В Qt есть удобнейший компилятор ресурсов rcc, при этом работа с запакованными им файлами поддерживается на уровне всяких QFile, QImage и прочих подобных и никакие трюки вида sizeof(shit) / sizeof(*shit) для определения размера не нужны.

Неужели этот #embed будет чем-то схожим по удобству?

P.S. Прошёл по ссылке:

static const char sound_signature[] = {
#embed <sdk/jump.wav>
	};
	static_assert((sizeof(sound_signature) / sizeof(*sound_signature)) >= 4,
		"There should be at least 4 elements in this array.");

Мда, очень «удобно». Лучше бы этот #embed сразу генерировал массив с именем основываясь на имени файла и размером константой/дефайном, как работают xxd или тот же GIMP, а не вот это вот всё.

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

Лучше бы заместо

for (int i = 0; i < 3; ++i)
{ printf("%d\n",array[i]); }

Впендюрить в стандарт

for (auto el in array)
    print(“{}”, el);

А также функ программирование навроде

map(array, print("{}"))

Неужели нужно это ждать в C50?

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

print уже в стандарте С++23.

И он даже автоматом стандартные контейнеры выводит :)

  std::print("Привет, {}! У вас {} писем", username, email_count);

  std::print("{}", std::vector<int>{1, 2, 3});  // Вывод: [1, 2, 3]
  std::print("{}", std::set<int>{1, 2, 3});     // Вывод: {1, 2, 3}
  std::print("{}", std::pair{42, 16});          // Вывод: (42, 16)

  std::vector v1 = {1, 2};
  std::vector v2 = {'a', 'b', 'c'};
  std::print("{}", std::views::zip(v1, v2));   // [(1, 'a'), (2, 'b')]
fsb4000 ★★★★★
() автор топика
Последнее исправление: fsb4000 (всего исправлений: 1)