Всё началось на второй паре по системному программированию. Нам дали задачу: написать CLI-утилиту для анализа логов - парсить файл, фильтровать записи по уровню ошибок, считать статистику, выводить красиво в консоль. "Ну понятно", - открыл я vim и началось мое долгое приключение...
Неделя. Две. Утилита называлась logz, она умела читать логи nginx и apache, фильтровать по уровню (DEBUG, INFO, WARN, ERROR), по дате, по IP, выводила топ адресов с наибольшим числом ошибок, рисовала простенький bar-chart прямо в терминале через unicode-символы. Только вот я сидел как-то вечером, запустил wc -l main.c - 3147 строк. И смотрел на это число минуты три с таким лицом - O_O.
Сама утилита работала. Но открывая её осознаешь что - это месиво. Одна функция process_file на 400 строк. Сегфолты раз в неделю. Valgrind как лучший друг. И каждый раз когда надо добавить фичу - сначала полчаса вспоминаешь что вообще происходит в коде.
Потом я случайно прочитал пост про Zig на lobste.rs. Заинтересовался и попробовал. Через месяц у меня была та же утилита, но теперь на 1089 строках, которая работала быстрее и не падала.
Тут я понял что вот золотая жила и расскажу о том - зачем Zig, как переписывал, где облажался и что вышло в итоге.
Постановка проблемы: что конкретно бесило в C
Я не скажу что "C - это плохой язык", потому что это чушь. Но конкретно мои боли в этом проекте:
Память вручную. Каждый malloc - это обязательство. Написал функцию, она вернула строку - не забудь освободить. Добавил ранний return по ошибке - не забудь освободить до него. Я честно раза три ловил утечки памяти в logz. Valgrind спасал, но ты не запускаешь valgrind - ты просто пушишь.
Сразу скажу что сегфолты - это когда прога пытается залезть в память к которой ей нельзя.
Сегфолты. Это отдельная история. Утилита читала файлы гигабайтами, и где-то в середине - Segmentation fault (core dumped). Дебажишь час, находишь: буфер на 256 байт, а строка лога оказалась 300. Классика. Починил - появился другой: off-by-one в парсере дат. Я реально начал видеть сегфолты во сне.
Bil-система. Мой Makefile работал, пока я его помнил. Через месяц открываешь - что это вообще такое? Плюс make иногда говорит «up to date» хотя ты только что изменил хедер. Да, знаю про -MMD, но это ещё один уровень вещей которые надо держать в голове.
Объём кода. Элементарный парсер строки вида 2026-01-17 ERROR [nginx] 192.168.1.100 500 на C - это функция строк на 50. Потому что: strtok или ручной парсинг, проверки NULL на каждом шагу, strncpy с ограничением длины, освобождение временных буферов... Это не сложно, но это много кода ради простой вещи.
Обработка ошибок. Функции возвращают -1 или NULL при ошибке, смысл ошибки - в errno или нигде. Пишешь цепочку if (result < 0) { perror("..."); return -1; } и либо ты теряешь контекст, либо таскаешь его через все уровни вручную. 3000 строк такого кода - это уже нечитабельно.
Почему Zig, а не Rust?
Rust читал месяц. Крутой, но borrow checker для утилиты которая читает файл и пишет в stdout - избыточен. Хотел C по духу, но без боли.
Zig зашёл за:
Нет hidden control flow -
defer file.close()прямо в коде, ничего за кулисамиОшибки через типы -
!Tзначит "либо значение, либо ошибка", компилятор не даст проигнорироватьКросс-компиляция из коробки -
zig build -Dtarget=x86_64-windowsбез тулчейновМаленький проект собирается за секунду
Кратко: C - это контроль ценой боли, Rust - это безопасность ценой сложности, Zig - это C, только с нормальными инструментами.
Архитектура
logz - CLI для анализа access.log / error.log:
logz --file access.log --level ERROR --from 2026-01-17 --top-ip 10
Pipeline из пяти модулей, данные текут строго вниз:

В C у меня было иначе: одна функция process_file делала всё сразу. Добавить новый формат лога = переписывать её всю
Код: Zig рядом с C
1.Парсинг аргументов
С +- 80 строк было
// args C int parse_args(int argc, char **argv, Config *cfg) { for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--file") == 0) { if (i + 1 >= argc) { fprintf(stderr, "error: --file requires a value\n"); return -1; } cfg->filename = argv[++i]; } else if (strcmp(argv[i], "--level") == 0) { if (i + 1 >= argc) return -1; cfg->level = parse_level(argv[++i]); if (cfg->level < 0) { fprintf(stderr, "error: unknown level\n"); return -1; } } else if (strcmp(argv[i], "--top-ip") == 0) { if (i + 1 >= argc) return -1; cfg->top_ip = atoi(argv[++i]); if (cfg->top_ip <= 0) return -1; } // еще параметры } return 0; }
Zig-версия - стало +- 40 строк
// args.zig const Config = struct { filename: []const u8 = "", level: ?LogLevel = null, top_ip: u32 = 10, from_date: ?i64 = null, }; fn parseArgs(allocator: std.mem.Allocator) !Config { var args = try std.process.argsWithAllocator(allocator); defer args.deinit(); var cfg = Config{}; _ = args.next(); // пропускаю имя программы while (args.next()) |arg| { if (std.mem.eql(u8, arg, "--file")) { cfg.filename = args.next() orelse return error.MissingValue; } else if (std.mem.eql(u8, arg, "--level")) { const lvl = args.next() orelse return error.MissingValue; cfg.level = try LogLevel.parse(lvl); } else if (std.mem.eql(u8, arg, "--top-ip")) { const n = args.next() orelse return error.MissingValue; cfg.top_ip = try std.fmt.parseInt(u32, n, 10); } } return cfg; }
orelse return error.MissingValue - одна строка вместо трёх проверок. Ошибка явная, не -1.
2.Парсинг строки лога
С-версия +-65 строк
// parser.С LogEntry *parse_line(char *line) { LogEntry *entry = malloc(sizeof(LogEntry)); if (!entry) return NULL; char *saveptr; char *token = strtok_r(line, " ", &saveptr); if (!token) { free(entry); return NULL; } if (parse_timestamp(token, &entry->timestamp) != 0) { free(entry); return NULL; } token = strtok_r(NULL, " ", &saveptr); if (!token) { free(entry); return NULL; } entry->level = level_from_string(token); if (entry->level == LOG_LEVEL_UNKNOWN) { free(entry); return NULL; } // ещё 40 строк в том же духе return entry; } // Важно: вызывающий обязан вызвать free(entry) потом
Zig-версия +- 35-40 строк
// parser.zig const LogEntry = struct { timestamp: i64, level: LogLevel, source: []const u8, ip: []const u8, status: u16, }; fn parseLine(line: []const u8) !LogEntry { var iter = std.mem.splitScalar(u8, line, ' '); const ts_str = iter.next() orelse return error.InvalidFormat; const timestamp = try parseTimestamp(ts_str); const level_str = iter.next() orelse return error.InvalidFormat; const level = try LogLevel.parse(level_str); const source = iter.next() orelse return error.InvalidFormat; const ip = iter.next() orelse return error.InvalidFormat; _ = iter.next(); // пропускаю HTTP-метод и путь const status_str = iter.next() orelse return error.InvalidFormat; const status = try std.fmt.parseInt(u16, status_str, 10); return LogEntry{ .timestamp = timestamp, .level = level, .source = source, .ip = ip, .status = status, }; }
Чем лучше: нет malloc, нет free, нет strtok с его глобальным состоянием. Функция либо возвращает валидный LogEntry, либо ошибку - и это написано прямо в сигнатуре !LogEntry. Вызывающий не может случайно забыть освободить память.
3.Работа с файлами и defer
// main.zig pub fn processFile( allocator: std.mem.Allocator, path: []const u8, cfg: Config, ) !Stats { const file = try std.fs.cwd().openFile(path, .{}); defer file.close(); // закроется при любом выходе из функции var buffered = std.io.bufferedReader(file.reader()); var reader = buffered.reader(); var stats = Stats.init(allocator); defer stats.deinit(); var line_buf: [8192]u8 = undefined; while (try reader.readUntilDelimiterOrEof(&line_buf, '\n')) |line| { const entry = parseLine(line) catch continue; // битые строки просто пропускаем if (cfg.matches(entry)) { try stats.add(entry); } } return stats; }
В C мне надо было писать fclose(file) перед каждым return, а их у меня было четыре разных в этой функции. Каждый раз думать: "я закрыл файл?". С defer эта задача исчезла.
Бенчмарки
Тестовый файл: 5 млн строк, +-800 МБ.
Метрика |
С |
Zig |
Время выполнения |
4.2 сек |
2.8 сек |
Размер бинарника |
47КБ |
32КБ |
Пиковая память |
124МБ |
89МБ |
Время сборки |
3.1 сек |
1.4 сек |
Строк кода |
3147 |
1089 |
Zig быстрее на треть - просто потому что я сразу написал нормальный bufferedReader, а в C у меня был fgets без буферизации. Строк кода в три раза меньше - это главный результат.
"Грабли"
Allocators непривычны. Поначалу лепил везде page_allocator. Потом открыл ArenaAllocator - для CLI-утилиты идеально: выделяешь сколько хочешь, в конце arena.deinit() и всё сразу освобождается.
Строки - слайсы, не char*. []const u8 не имеет нуля в конце. Передаёшь в C-функцию напрямую - UB. Надо .ptr и убедиться что строка null-terminated.
Ошибки компилятора длинные. Сообщение на 20 строк - читай только первую, остальное трассировка. Уже привыкаешь.
Язык меняется. Zig пока не 1, я на 0.13. Примеры из интернета 2022 - 23 года часто не компилируются - всегда смотри официальную документацию.
Выводы по Zig
Стоит ли переходить на Zig в 2026?
Естественно да, если: пишешь CLI-утилиты, системные инструменты, что-то встраиваемое. Нужен контроль над памятью, но без сегфолтов каждую неделю. Хочешь кросс-компиляцию без боли. Устал от Makefile.
Лучше остаться на C, если: работаешь с большой существующей C-кодовой базой и интеграция не нужна. Или нужна максимальная стабильность языка - пока не 1, API может меняться между версиями.
Лучше взять Rust, если: проект большой и долгоживущий, важна экосистема (cargo + crates.io несравнимо богаче), работаешь в команде где Rust уже знают.
Для меня Zig занял нишу: "хочу писать низкоуровневый код без страданий". Три месяца назад я смотрел на 3000+ строк C и думал - ну это всё. Сейчас у меня 1089 строк Zig, утилита работает быстрее, и я понимаю каждую строку кода.
Если хочешь попробовать - ziglang.org. Начни с zig init, напиши hello world, потом попробуй открыть и построчно прочитать файл. Язык небольшой, стандартная библиотека читается за вечер.
Вот и все, напишите в комментах если было интересно.Буду рад если кому-нибудь это поможет и он будет пользоваться напостоянке.
Комментарии (49)

Siemargl
05.04.2026 11:33Удивлён, что версия на Zig получилась короче - он более многословный.
Для парсинга аргументов на С стоило тоже взять готовую библиотеку. Сравнение было бы корректнее
На С тоже элементарно делается defer макросами
Но все же Zig это язык уже нового поколения.
И вообще - это перевод? Потому что актуальный Zig 0.16

atd
05.04.2026 11:33Я вот на 0.14 сижу и доволен ;) Ну либо автор написал код какое-то время назад, а статью только сейчас.

evgeniy_kudinov
05.04.2026 11:33К сожалению до релиза 1.0 далеко, когда выйдет уже и не нужен будет наверное.

MainEditor0
05.04.2026 11:33Так ему уже 10 лет, они его полируют, ломают (-ли) совместимость, чтобы к релизу выдать что-то готовое... Не уверен насчёт достоверности, но, вроде, в этом году выйдет стабильный релиз v1.0

evgeniy_kudinov
05.04.2026 11:33LLM выдала со ссылкой на Telegram-канал: "По некоторым прогнозам, версия 1.0 языка программирования Zig выйдет не раньше 2029 года".
Я читал, что автор - перфекционист и стремится создать надёжный инструмент. Однако процесс версионирования может затянуться на следующие 10 лет. За это время многое может измениться в разработке ПО, учитывая быстрый прогресс LLM.
Если у вас есть точная информация о дате выхода версии 1 из roadmap, буду признателен.

garm
05.04.2026 11:33Язык С не прибит гвоздями к Makefile, там уже много разных альтернатив придумали.
И мне интересно, почему zig , а не c++?

domix32
05.04.2026 11:33Чтобы не страдать с Makefile, cmake, automake, premake и прочими сборочными извращениями, которые современные языки решают обычной сабкомандой init. Уж лучше какой-нибудь cppfront взять.

Siemargl
05.04.2026 11:33Ох уж эти страдатели, которые маке не осилили)

domix32
05.04.2026 11:33Вот его-то как раз проще всего освоить. В сравнении с Zig, который требует только Zig для контроля зависимостей это определённо жирный минус. А уж если один пишет на cmake, второй на autotools, а третий либу собирает через conan веселье умножается пропорционально и можно шутить что неосиливатель маке не осилил ещё каких-то три-четыре сборочных системы. Это ж куда важнее, чем просто писать прогамму на языке.

Siemargl
05.04.2026 11:33Кстати, попадаются проекты на С, которые используют Zig чисто как систему сборки.
Он ещё и кэширует (в принципе, так же как и маке) сборку автоматически.
А вот с подгрузкой сторонних пакетов лично не пробовал, но вроде возможности есть.
Так что в плюс. Но каких то особенных прорывов нет.

domix32
05.04.2026 11:33используют Zig чисто как систему сборки.
Это как раз один из их способов саморекламы. Многие хвалят компилятор Си у zig за понятные ошибки да и вообще за удобную интероперабельность с Си. Похожую поддержку встречал только у D. Одно время build.zig пытались контрибутить во многие популярные репы на си. Кто-то принял, кто-то послал на три буквы, чтобы не заниматься поддержкой ещё одного языка в проекте. Слышал, что некоторые сишные проекты решили использовать целиком инфраструктуру zig для сборки кода, но живьем не встречал.

durnoy
05.04.2026 11:33Rust читал месяц. Крутой, но borrow checker для утилиты которая читает файл и пишет в stdout - избыточен.
Так ведь если утилита в одном исходном файле, то borrow checker вы даже не заметите.

SpiderEkb
05.04.2026 11:33В C мне надо было писать
fclose(file)перед каждымreturn, а их у меня было четыре разных в этой функции.Множественный return вообще не очень хорошая практика. Корректнее использовать единую точку выхода.
К сожалению, в языках где нет возможности определять блок
on-exit; // выполняем все необходимые перед выходом действия ... return;куда передается управление поде каждого return в функции, или хотя бы поддержки сабрутин (аналог подпрограммы в бейсике - отдельный блок кода внутри функции, вызываемый без создания нового уровня стека и не имеющий собственных аргументов и локальных переменных), позволяющий организовать точку выхода
begsr srExit; // выполняем все необходимые перед выходом действия ... return; endsr;и позволяющий вместо
if (...) return;использовать
if (...) exsr srExit;использование единой точки выхода может потребовать определенной организации кода для избежания многоуровневых if !error.
Функции возвращают -1 или NULL при ошибке, смысл ошибки - в errno или нигде.
Это, мягко говоря, не так. Есть понятие "структурированной ошибки". В простейшем виде выглядит вот так:
typedef struct Qus_EC { int Bytes_Provided; int Bytes_Available; char Exception_Id[7]; char Reserved; char Exception_Data[]; /* Varying length */ } Qus_EC_t;Передается аргументом в функцию. На выходе достатчоно проверить
if (Qus_EC.Bytes_Available) { // функция заполнила ошибку ... };Bytes_Provided тут - размер структуры (определяется размером блока дополнительных данных Exception_Data) ; Bytes_Available = 0 - ошибки не было, Bytes_Available > 0 - ошибка была; Exception_Id - код ошибки; Exception_Data - блок дополнительных данных произвольного размера, связанных с конкретной ошибкой.
Остальное тоже весьма спорно. Например
В C у меня было иначе: одна функция
process_fileделала всё сразу. Добавить новый формат лога = переписывать её всюА зачем было делать именно так? Почему не разбить эту функцию на несколько более мелких? Например, "диспетчер", определяющий формат лога + набор парсеров под разные форматы? Новый формат - пишем парсер и добавляем его в таблицу парсеров диспетчера.
Такое ощущение, что кинулись писать на С особо не продумав что и как, поплясали с бубном на граблях и потом уже, получив понимание что и как, переписали все на Zig. И 90% "бонусов" не от того, что Zig лучше, а от пришедшего понимания тонкостей задачи.

ValeryIvanov
05.04.2026 11:33Это всё круто, но как ты ошибки не возвращай, всегда будет одна проблема - компилятор не скажет, где ты забыл обработать ошибку. Один раз не проверил что вернула функция, у тебя с большой вероятностью сегфолт, который ещё попробуй исправь. zig такого не позволяет. Хотя, на самом деле, zig тоже не очень безопасный в этом плане. Забыл освободить ресурс через defer и прога падает или память утекает, но в нём хотя бы есть DebugAllocator и стек вызовов, что позволяет ошибки отловить достаточно рано. То есть на корню все проблемы системного программирования zig не решает, но он однозначно делает многие вещи лучше C.

SpiderEkb
05.04.2026 11:33Ну я не спорю. Писать на С требует тренировки мозга - многое приходится в голове держать. Это только годами практики нарабатывается до автоматизма.
В этом плане Rust интереснее, хотя и требует привыкания к заложенным в нем концепциям.
А структурированная ошибка - это целая концепция на уровне системы.
Есть т.н. message file - таблица где содержится код ошибки, ее текстовка (с возможностью подстановки параметров), уровень серьезности (например, 0 - информация, 10 - предупреждение, 20 - критическая). Есть системное API куда передается вот эта структура, содержащая код и значения параметров для подстановки. API по коду находит в message file данную ошибку, берет ее текстовку, подставляет параметры и возвращает полный текст и уровень серьезности.
Разрабатывая сое ПО вы всегда можете расширять message file добавляя туда характерные для вашего ПО ошибки со своими кодами. Функция в общем случае возвращает получилось/не получилось. Если не получилось, вы можете или анализировать ошибку по коду, или же дернуть API и получить полный текст (уже с подставленными параметрами) и дальше выводить его на экран, в лог или еще куда вам нужно.
Плюс эта же ошибка может пробрасываться в виде исключения (языкового или системного, если таковые поддерживаются).

domix32
05.04.2026 11:33Как-то так по итогу оно и вываливается во втрое больший код, потому что сначала нужно написать систему, чтобы было хорошо - то арену добавь, то работу с массивами скопипасти, то обработку ошибок допиши...

SpiderEkb
05.04.2026 11:33Если речь идет о долгосрочном проекте который потом придется поддерживать и развивать, то оно того стоит.
Ну или если себе строишь набор рабочих инструментов на долгое время.
И в любом серьезном проекте работа с ошибками занимает достаточно большую часть. Если не делать как современные вебклепатели - на все одна ошибка "что-то пошло не так, попробуйте как-нибудь потом"

domix32
05.04.2026 11:33Если речь идет о долгосрочном проекте который потом придется поддерживать и развивать, то оно того стоит.
Из чего следует необходимость учить ещё один какой-нибудь язык для того чтобы собирать код на си. Можно конечно использовать какой-нибудь nob, чтобы иметь только компилятор в зависимостях, но там свои квирки и segafult приветы будут.

SpiderEkb
05.04.2026 11:33Ну если по хорошему, то использовать более одного языка в одном проекте - нормально.
Я вот пишу как минимум на двух (то, что в прод идет). Ну и Rust немного для себя... Правда, языки у меня сильно разные. Один хорош для работы с БД и всяких коммерческих расчетов (это основной), но если что-то более низкоуровневое, то там С/С++ лучше.
Часто бывает что один кусок задачи лучше и быстрее решается на одном языке, другой - на другом.

d3d12
05.04.2026 11:33Одна точка выхода:
if (error1) goto one_exit; ... if (error2) goto one_exit; ... if (error3) goto one_exit; ... one_exit: ...release actions...Если кому то режет глаз goto, то:
while (TRUE) { if (error1) break; ... if (error2) break; ... break; } ...release actions...Есть еще вариант с исключениями, но лично я их использование считаю дурным тоном.

SpiderEkb
05.04.2026 11:33Есть еще вариант с исключениями, но лично я их использование считаю дурным тоном.
Да, согласен. Исключения штука ресурсоемкая. В высоконагруженных системах использование их стоит свести к минимуму. Только в случае крайне необходимости.
Когда условий много делал примерно так:
for (stage=0; stage < MAX_STAGE; stage++) { switch (stage) { case 1: ... блок операций где может возникнуть прерывающая ошибка ... break; case 2: ... блок операций где может возникнуть прерывающая ошибка ... break; ... } if (error) break; }Чуть хуже с точки зрения производительности, но лучше с точки зрения читаемости. Плюс то, что находится в блоках case вынести в отдельные функции
Но суть, да, в том чтобы обеспечить единую точку входа и единую точку выхода.

AlexSky
05.04.2026 11:33do { ... блок операций где может возникнуть прерывающая ошибка ... break; ... блок операций где может возникнуть прерывающая ошибка ... break; } while (0);А почему не так?

SpiderEkb
05.04.2026 11:33Потому что вам придется после каждого блока проверять if (error) break;
А здесь на каждом обороте цикла отработает один блок (тот, что идет по соотв. номеру) и после этого проверится ошибка.

Weselton
05.04.2026 11:33Наброшу немного за Rust
1)
Ошибки через типы -
!TВ Rust еще круче есть - Result<T>: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#recoverable-errors-with-result
2)
Кросс-компиляция из коробки -
zig build -Dtarget=x86_64-windowsбез тулчейновВ Rust: https://crates.io/crates/cargo-zigbuild
3)
Маленький проект собирается за секунду
В Rust - за доли секунд
4)
Rust - это безопасность ценой сложности
Это ложно. Корректный код на Rust в миллиарды раз проще писать, чем на C, Zig и, даже, Go. Проверено
5)
1089 строк на Zig
На Rust вышло бы и того меньше за счет отсутствия defer (это "фичей" назвать трудно, если честно; только в ироничном ключе), функционального подхода и удобнейших инструментов для работы со строками
6)
Ошибки компилятора длинные
В Rust прекрасные ошибки от компилятора, часто содержащие примеры исправлений. На зависть многим языкам
7)
Стоит ли переходить на Zig в 2026?
Почти в любом случае - нет, железобетонно. Нужен язык, использовать который можно без боли, быстрый, без gc - Rust, без серьезных альтернатив
Рекомендую, если целью является обучиться крутому инструменту production-ready и стать востребованным разработчиком, изучить Rust и/или Go. C - deprecated, Zig - тупик.
ИМХО
PS: вспомнилось мне интервью на youtube-канале ThePrimeTime с Алексеем Кладовым о Zig и его фичах. Зашла речь про то, что Алексею понадобилось быстренько написать небольшой инструмент для работы с большим строковым файлом. Он ответил, что выбрал Rust. Очень показательно )
https://www.youtube.com/watch?v=V8Bg55lTUCw&t=3701s
SpiderEkb
05.04.2026 11:33С Rust есть "всего лишь одна маленькая проблема" - нужно вникнуть в заложенные в нем концепции, принять их, немного перестроить мозги. И после этого работа с ним становится простоя и естественной.
Но на это требуется время, сразу с наскока может не получиться - пока не проникнешься, все будет казаться мучительно и больно.

domix32
05.04.2026 11:33На Rust вышло бы и того меньше за счет отсутствия defer
Скорее всего не стало бы меньше а +/- столько же, сколько и у Zig, если писать единым rs. Обработка result наверняка заполнила эти пробелы.

AngryEvilCookie
05.04.2026 11:33Парсил несколько гигов хмлников на шарпе за 5 секунд, от проца и ио конечно зависит, но чистый си это всегда геморрой конечно. Не знаю кто такой зиг, но если бы дожал на си, было бы быстрее.

okhsunrog
05.04.2026 11:33Читаю статью - и мозг постоянно цепляется за нейросетевые паттерны текста. Автор, признайся честно - нейросетка писала статью?

zum
05.04.2026 11:33Очевидно, что это вывод LLM. А так как автор студент, то меня преследует смутное сомнение, что это один из тех случаев, когда преподаватель ставит задачу "написать на хабр". Сколько раз так уже было.
Страшная, конечно, смесь - студент и LLM.

UFO_01
05.04.2026 11:33пишешь CLI-утилиты, системные инструменты, что-то встраиваемое
Ну не знаю, не знаю, как-то сомнительно если честно. Для перового и второго лучше взять что-то из троицы C++, Rust, Go. Для встраиваемых систем можно использовать Rust если уже пишешь на нём, если же до этого писал на C/C++, смысла переходить особо нет, максимум какую головную боль вылечишь - безопасный код писать можно, но ты не обязан.
И моя личная головная боль - сертификация по EN 50128, где по факту C это стандарт, он просто самый предсказуемый и проверяемый, и сертификация под него дешевле, а Ferrocene пока не дотягивает. Тем более что зачастую есть только компилятор для C99, о существовании C++ разработчики не слышали, и приходится терпеть терпеть, как например для 8-16-разрядных контроллеров. А с учётом жизненного цикла кода в 25 лет, Rust или что-то другое я увижу не скоро.

Siemargl
05.04.2026 11:33сертификация по EN 50128
C23 самую большую дырку с массивами закрыл. И с многопоточкой поработали
Он раньше пройдёт все сертификации.
А Раст туда попадет не раньше чем no-panic и nostd стандартизуют
Zig выигрывает у многих для эмбеда за счёт идеологии - никаких скрытых действий (аллокаций, паник, исключений итп) и кросс компиляции из коробки.

FlyingDutchman2
05.04.2026 11:33А если переписать эту утилиту с zig на Python, получится еще в два раза меньше строк кода.

domix32
05.04.2026 11:33И время работ с гигабайтными файлами сократится с пары секунд до жалких минут, да.

d3d12
05.04.2026 11:33И производительность упадет раз так в 1000.

kukovik
05.04.2026 11:33Сразу скажу что сегфолты - это когда прога пытается залезть в память к которой ей нельзя.
Тут надо уточнить, что если сегфолта нет (то есть прога залезла в память, к которой ей можно), это все равно не исключает ошибки. Потому как не факт, что это именно та часть памяти, которая подразумевалась.

agmt
05.04.2026 11:33Нет hidden control flow -
defer file.close()прямо в коде, ничего за кулисами
В языках без gc деструктор выглядит безопаснее и понятнее

Siemargl
05.04.2026 11:33Язык без GC и объектов. Хм, дайте подумать....
Приятнее, да=) для птиц

SpiderEkb
05.04.2026 11:33На самом деле gc нужен там, где есть активная работа с динамической памятью. Которая в целом отрицательно сказывается на производительности есть это высоконагруженная система (чтобы хоть как-то это нивелировать начинаются пляски с кастомными аллокаторами).
Поэтому языков, где динамическая работа с памятью сведена к минимуму, хватает. И GC там просто не нужен.
DSoap
Хм.. Как будто для такой задачи go может еще лучше подойти, что думаете?
gev
Haskell же!
Siemargl
Тоже варианты (D, Go, Rust)
Еще есть c# aot, который специально для этого. И вполне эффективный Nim, если нра Питон - синтаксис.