Знакомство

Честно говоря, язык Си был одним из тех языков, которые я начал учить просто потому, что мне это срочно понадобилось. Я работал в одной компании, где в одном из программных компонентов использовался Си, и мне надо было дописать функционал этого компонента. Ну вот так и случилось, что мне впервые пришлось довольно быстро разобраться с сишным кодом.

Через несколько лет, я решил заполнить пробелы и более серьезно занялся его изучением. Книжка K&R в одну руку, gcc под другую и через 2 недели я уже переписал в учебных целях сниппет из руководства по библиотеке libcurl. В том примере, содержимое страницы загружалось в буфер, который представлял из себя структуру из указателя на строку и целого числа для указания ее длины. Для лучшего понимания работы с указателями, я решил переписать этот пример без использования структуры. Я взял указатель на строку, который указывал на динамически выделяемую и реаалоцируемую память и писал туда, попутно реаллоцируя когда это было нужно. Учитывая, что моей задачей было загрузить только текстовые данные, размер буфера я контролировал через функцию strlen(). Как упражнение это было очень полезно т. к. попутно нужно было понять что такое «указатель на указатель на строку» (char**), ну и на практике понять что такое «нуль-терминированная строка» и как с ней работать. Кстати, вот этот сниппет - https://curl.se/libcurl/c/getinmemory.html

Я не могу похвастаться какими-то большими проектами на Си т.к. в основном приходилось заниматься мелким системным программированием, а также написанием и правкой всяких служебных тулзов в основном связанных с сетевым стэком в Linux и Windows. Например, доставшийся мне однажды по наследству самописный bgp-route-коллектор. Не могу сказать, что я к этому стремился "писать Си-код" , но во многом я нахожу это интересным и познавательным.

В виду того, что тема языка Си остается актуальной — за последнее время видел много видео на ютубе и недавно статью здесь про указатели типа void*, да и много других материалов — решил изложить несколько существеных, на мой взгляд, замечаний о Си в наши дни, и почему не стоит чураться писать на нем

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

Указатели типа void*

Будем честны — это своего рода «синтаксический сахар». В первом издании K&R его нет, и эти указатели появляются позже(в третьем издании они уже есть). И из объяснения там вполне можно понять причину по которой они появились. В противном случае нам бы пришлось пользоваться указателями на строку, которые в этом смысле удобны. На x86 один байт это char, вот и массив байт будет char[]. Так ведь? Но такой синтаксис может вводить в заблуждение, ведь, на уровне чтения кода сложно различить char* который указывает на нуль-терминированную строку и такой же char* который указывает на набор данных, который необязательно может быть ею представлен. Кстати, в сниппете, о котором я говорил выше, указатель void* используется для передачи указателя на структуру в callback-функцию, где этот указатель приводится к указателю на структуру.

WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
  size_t realsize = size * nmemb;
  struct MemoryStruct *mem = (struct MemoryStruct *)userp;

Согласитесь, синтаксис более наглядный, чем если бы мы использовали char* ? Конечно, можно возразить, что все равно, синтаксис не дает представления о том, на что ссылается указатель типа void*, но с другой стороны это дает свободу передавать в функцию указатель на что угодно.

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

Длина массивов

О, да! Здесь было сломано немало копий. Читать или писать за границами массивов — это то, что сделать очень легко в Си. Но на практике я использую два очевидных правила, которые помогают ввести достаточный контроль:

  1. массив объявленный в стэке должен быть фиксированной длины (соответственно запись и чтение в массив контролируется с помощью числовой константы, которая задает размерность массива)

  2. массив объявленный в куче лучше поместить в структуру, в которой будет два поля — ссылка на сам массив и целое число с помощью которого будем контролировать размерность массива

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

Батарейки в комплект не входят

Тут все просто — или приходится писать самому, или искать библиотеку. Моя установка в этом случае такова, что если пишешь на Си, то будь готов принять и сишное понимание свободы. Здесь у меня есть практический совет и мечта. Практический совет — нарабатывайте свою библиотеку часто используемого кода, найдите и пользуйтесь чужими там, где это возможно и разумно. Это и организует и упростит вашу работу. Мечтаю же я все же о подобии CPAN для Си кода. Конечно, есть поиск по Интернету и по гитхабу, но все же централизованный каталог типа CPAN для Perl — это было бы классно. В некоторых моментах помогала библиотека Apache Portable Runtime, но большого опыта в ее использовании у меня нет, поэтому не могу гарантировать, что там все работает классно и быстро.

Коллаборация — это добро

Во многих языках есть возможности взаимодействия с Си-кодом. Еще когда-то давно для меня было удивительно найти в perl-коде, который подготавливал логи телефонной станции к отправке в биллинг, участок кода, который вызывал функцию в написанной на Си библиотеке. Функция, кстати выполняла нормализацию телефонных номеров и приведения их к единому виду. И у такого решения была причина — этот код работал очень быстро.

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

Развивайтесь и исследуйте

Я взял себе за правило, что если даже мне не нужно написать что-то на Си, то я обязательно изучу код чего-то, что мне интересно на Си. В свое время читал монографию Роберта Лава про ядро Linux, было интересно посмотреть как работает планировщик. В вещах менее специфических тоже можно почерпнуть много нового интересного, а может и, наконец, понять как что работает. Я например, долгое время не понимал в чем разница между симметричным и асимметричным шифрованием, и что такое режим работы симметричных алгоритов. Посмотрев как работать с API криптографических библиотек я понял то, что для меня было непонятно. В целом существует множество интересных и полезных тем для изучения. Любое исследование чужого кода, особенно если он общеиспользуемый — это полезно (например libc).

Не верьте рекламе

Не торопитесь нырять в Си, до тех пор пока в этом нет нужды. Если вы только начинаете программировать, то Си — это точно не ваш выбор. На своем опыте, могу сказать, что изучение Си для меня совпало с моментом, когда нужно было и немного понять ассемблер. Три первых года — это вам точно не понадобится. Но далее, когда станете взрослее, и если не бросите кодить, то хотя бы для общего развития рекомендую базово разобраться в Си и ассемблере для x86. Это поможет начать путь к оптимизации кода. Конечно, ассемблерные вставки вы не начнете писать, но хотя бы более глубоко поймете как компьютер исполняет код.


* * *

Пожалуй это все, в рамках того, чтоб не вызвать споров о том какой язык «лучше». Надеюсь, кому-то, кто только начинает свой путь в Си, эти заметки пригодятся. Си для меня это та база, на которой стоит многое с чем я работаю, поэтому, какой-бы он ни был, это почти необходимость понимать его. Есть ситуации, где невозможно сбежать на какой-то другой язык, а надо решить задачу на том языке, на котором написан код. У меня так случилось, что даже в моих прикладных задачах часто встречается Си.

Комментарии (53)


  1. unreal_undead2
    23.10.2024 09:44

    но все же централизованный каталог типа CPAN для Perl — это было бы классно

    Есть ещё нюанс с лицензиями, учитывая, что на C пишется много закрытого кода, который отдаётся конечным пользователям. И есть большая разница между GPL/LGPL/Apache и т.д., иногда приходится советоваться с корпоративными юристами о возможности использования конкретной библиотеки в кокнретном случае.


    1. arseniiv Автор
      23.10.2024 09:44

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


      1. unreal_undead2
        23.10.2024 09:44

        На том же Perl как то сложно отдать рабочий код без исходника. И используется он больше для внутренних целей, чем во внешних продуктах.


        1. arseniiv Автор
          23.10.2024 09:44

          Плюсы, Шарп, Раст, Джава?


          1. unreal_undead2
            23.10.2024 09:44

            Из них разве что у Раста есть центральный репозиторий. Но язык молодой ещё, не знаю насколько широко в коробочном софте используется.


            1. slonopotamus
              23.10.2024 09:44

              Из них разве что у Раста есть центральный репозиторий.

              Эээ?

              Плюсы - conan, vcpkg
              C# - nuget
              Java - mvnrepository


              1. unreal_undead2
                23.10.2024 09:44

                Насколько оно популярно среди разработчиков софта - в смысле, все ли спешат выкладывать свежие (и держать старые) версии в этих репозиториях? Я за нужной C++ библиотекой скорее пойду на её родной github.


                1. slonopotamus
                  23.10.2024 09:44

                  Протестую, подмена тезиса. Репозитории есть? Есть.

                  Дальше сами ищите статистику, если хочется поиграть в демагогию. А то я вам покажу цифры, а вы "ну это не то измерено".


                  1. unreal_undead2
                    23.10.2024 09:44

                    Да, вижу что репозитории есть - с этим спорить не буду, спасибо за информацию. Вопрос в том, можно ли и стоит ли ими реально пользоваться в серьёзных проектах.


                1. VZNKN
                  23.10.2024 09:44

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


                  1. unreal_undead2
                    23.10.2024 09:44

                    То есть, скажем, https://github.com/microsoft/vscode все нужные зависимости оттуда подтянет ?


    1. arteast
      23.10.2024 09:44

      Этот нюанс есть везде, и это не аргумент против репозитариев (которые для C есть - vcpkg, conan навскидку).

      Для борьбы с лицензиями есть

      1) административные средства - библиотеки, грубо говоря, в продакшне не добавляются по желанию левой пятки. Сначала решается, добавлять ли каждую конкретную библиотеку себе в зависимости (оценивается, насколько она полезна, насколько она надежна, насколько активно поддерживается и развивается), и в самом начале этой оценки просто берем и смотрим на лицензию. Если она нас не устраивает - библиотеку не добавляем.

      2) технические средства. Для некоторых языков и некоторых билд-систем/систем управления зависимости/CI есть специальные инструменты (см. Software Composition Analysis), которые делают отчеты по зависимостям - появление новых версий, известных уязвимостей и багов, просто список всех зависимостей, и в том числе и compliance. Для каких-нибудь javascript, где в npm можно незаметно для себя получить по транзитивным зависимостям черта лысого, это актуально. Еще для некоторых лицензий типа BSD это актуально, когда их можно использовать в проприетарщине, но лицензия требует некоторых телодвижений в документации.


      1. arseniiv Автор
        23.10.2024 09:44

        Спасибо за подсказку с conan


      1. unreal_undead2
        23.10.2024 09:44

        Насколько понял, это скорее "метарепозитории" - там ссылки на другие репозитории, а не сам код. Так в принципе разные проекты с разными лицензияим могут уживаться. Вопрос только в том, кто эти списки репозиториев обновляет и насколько они актуальны - сходу вижу, что llvm в conan предлагается древней 13ой версии.


        1. arteast
          23.10.2024 09:44

          А какие есть "монорепозитории" уровня языка? Я что-то навскидку не припомню. Везде, вроде, ссылки на репозитории идут, и обычно дополнительно хранилище упакованных артефактов/пакетов; и соответственно у каждого конкретного пакета собственная лицензия.

          Обновляются они либо коллегиально в стиле OSS под управлением или ревью одной команды мейнтейнеров (как те же conan и vcpkg), либо, чаще, федеративно - у каждого пакета есть владелец, который его может обновлять (Rust - crates.io, Ruby - RubyGems, Perl - CPAN). В первом случае получаем лучшее качество, но более медленное обновление.


          1. unreal_undead2
            23.10.2024 09:44

            Разве в CPAN всё не в одном месте лежит?


            1. arteast
              23.10.2024 09:44

              Вообще да, но это техническая деталь хранения или представления пакета в API, а не семантическая деталь монорепозитория. К примеру, возьмем свежезалитый https://fastapi.metacpan.org/source/GBROWN/Net-RDAP-Server-0.02 . Выглядит как репозиторий, да. Но это не оригинальное местоположение исходников, а выгруженная в зеркало версия. Оно ничем не отличается от пакета Ruby или Python, кроме того, что мы видим не архив, а распакованную версию этого архива (включая метаинформацию в META.yml, которая указывает на собсно репозиторий и лицензию). Чем конкретно отличается CPAN от PyPI? Имхо ничем.


              1. unreal_undead2
                23.10.2024 09:44

                По крайней мере это давно устоявшееся место, про которое точно знают авторы пакетов и выкладывают свежие версии. В C/C++ таких традиций нет. Да и с точки зрения использования - при разработке коммерческого продукта для конечного пользователя надёжнее держать копии сторонних исходников у себя, аккуратно отслеживая обновления.


                1. arteast
                  23.10.2024 09:44

                  Увы, да. Стандартного репо нет. Про локальные копии тоже верно для любого языка - только не всякий язык это позволит сделать нормальным образом. Кстати, как vcpkg, так и conan это позволяют - можно наколдовать себе on-premise репу с только теми пакетами, что сами себе разрешили и проверили. Но требуется некоторая работа. А в некоторых языках наоборот, можно за секунду сделать pip install или там cargo install - и получить десяток свежих пакетов; зато потом сиди и разбирайся, что там нового и нет ли там привета, как было с каким-то npm пакетом.


                  1. unreal_undead2
                    23.10.2024 09:44

                    Вот как раз conan on-premise видел, до этой дискуссии не знал, что у него и центральный репозиторий есть.


  1. eptr
    23.10.2024 09:44

    Если заменить на char, то ничего не изменится:

    WriteMemoryCallback(char *contents, size_t size, size_t nmemb, char *userp)
    {
      size_t realsize = size * nmemb;
      struct MemoryStruct *mem = (struct MemoryStruct *)userp;

    В C имеется неявное приведение указателя на любой тип данных к указателю на void и обратно, поэтому с void'ом должно выглядеть так:

    WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
    {
      size_t realsize = size * nmemb;
      struct MemoryStruct *mem = userp;

    При этом неявном приведении "вложенность" указателя не имеет значения, поэтому можно написать такой код:

    int main(void) {
            void *p = &p;
            printf("%p\n", p);

    Выражение &p имеет тип указатель на указатель на void, но поскольку указатель на любой тип данных, даже если этот тип данных сам по себе указатель, неявно приводится к указателю на void, то это происходит и в данном случае.

    Это относится только к указателям на данные, поэтому указатель на функцию нельзя привести к указателю на void, точнее, можно, но это -- UB.

    Одной из причин может быть то, что размер указателя на функцию может быть больше размера указателя на данные.


    1. arseniiv Автор
      23.10.2024 09:44

      Да, это понятно. Сейчас лень искать уже эти файлы, но в каком-то случае может быть предупреждение, которое, впрочем, никак не повлияет на работоспособность кода. Но сегодня предпочитаю все же явно указывать приведение из void*, скорее для читабельности.


      1. eptr
        23.10.2024 09:44

        Сейчас лень искать уже эти файлы, но в каком-то случае может быть предупреждение

        Никакого предупреждения не может быть по поводу неявного приведения указателя на тип данных к указателю на void и обратно.

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

        Но сегодня предпочитаю все же явно указывать приведение из void*, скорее для читабельности.

        Это снижает читабельность, замусоривая код.


        1. arseniiv Автор
          23.10.2024 09:44

          Да, сейчас отыскал эти файлы на флэшке. Я оказывается вообще убрал приведение.


  1. le2
    23.10.2024 09:44

    Скорее всего всё идет к тому что Си и Си++ рептилоиды объявят вне закона. Запретят сертификацию автомобильной и прочей ответственной электроники с кодом на этих "небезопасных" языках. Естественно, всё в рамках недобросовестной конкуренции с недоразвитыми странами и в пользу ТНК.

    В остальном Си жив пока жив Posix. Хотя Linux и прочие ядра не написаны на Си, а на неком диалекте, в котором нет libc, есть ограничения на выделение памяти и прочие вещи, которые должны входить в Си.
    Для современного программирования на прикладном уровне применимость Си сомнительна. В эпоху многоядерных процессоров мало кто может показать многопоточный код на Си за который было бы не стыдно.


    1. DieSlogan
      23.10.2024 09:44

      https://github.com/netdata/netdata

      https://github.com/raysan5/raylib

      https://github.com/OISF/suricata

      https://github.com/redis/redis

      https://github.com/pbatard/rufus

      Как бы, не сказать, что прикладное, но такие системы подчас на питонах пишут. А тут Си и всё активные проекты.


    1. rukhi7
      23.10.2024 09:44

      В эпоху многоядерных процессоров мало кто может показать многопоточный код на Си за который было бы не стыдно.

      я бы с огромным интересом посмотрел многопоточный код "за который не стыдно" на любом языке, который только не логирует как мяукают котятки или лают собачки.

      Хотя Linux и прочие ядра не написаны на Си, а на неком диалекте,

      в стандарте С нет прерываний (как минимум), поэтому все что работает с аппаратными прерываниями выходит за пределы стандарта.

      С (язык) придумали чтобы абстрагироваться от работы на аппаратном уровне, но оказалось, что на С также удобно работать и на аппаратном уровне.


      1. le2
        23.10.2024 09:44

        ну, например, как решает задачи Гугл.
        Строится граф. Вершины и связи описываются в человекочитаемом виде - библиотека protobuf. По текстовым файлам .proto при сборке автоматически формируются объекты C++, то есть доп нагрузки при исполненении нет. Вершины могут быть написаны на разных языках, это позволяет система сборки bazel.
        В итоге утилизация ядер процессора очень хорошая. Программисту не нужно думать как все это распараллеливается.
        Въезжать в эту тему больно, но код выглядит изящно и понятно.


        1. nagayev
          23.10.2024 09:44

          А подробнее про это где-нибудь можно почитать?


          1. le2
            23.10.2024 09:44

            например https://habr.com/ru/articles/502440/
            собрать по первой части статьи bazel build //Source:HelloWorld
            Но то что удобно для огромных коллективов Гугла может быть очень больно для малых групп или одиночек.


    1. arseniiv Автор
      23.10.2024 09:44

      Хотя Linux и прочие ядра не написаны на Си, а на неком диалекте, в котором нет libc, есть ограничения на выделение памяти и прочие вещи, которые должны входить в Си.

      Мне интересно откуда такая информация, что ядро Linux написано не на Си. Я когда изучал как устроен планировщик, я увидел уйму Си-кода.

      И это вполне логично, что до того как ядро не инциировало кучу вещей, которые нужны для загрузки libc, ни о каком ее использовании не может быть и речи.

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

      Про ограничения памяти я не очень понял. Вы говорите про невозможность пользоваться верхней памятью? Не очень понимаю, почему Вы это пеняете непосредственно Си. Это ж вроде хардварные ограничения (вроде от режима процессора зависит, сейчас не помню)

      Про автомобильную электронику не слышал, но вот станции управления лифтами как-то обходятся вообще без линкуса. Там чип(скорее всего FPGA) со своим микрокодом и хардварной таблицей настроек.


    1. BoldDwarf
      23.10.2024 09:44

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

      Обработчики прерываний написаны в абсолютно подавляющем случае на C, даже низкоуровневые.

      libc как и прочие библиотеки не входят в сам язык, он прекрасно может работать без них, если они не нужны пользователю/программе. Ядру Линукс они не нужны.

      Многопоточный код на C надо уметь готовить и применять где нужно.

      Без понятия что там используется в автомобильной электронике но не удивлюсь если там работает free rtos, которая написана на C или VxWorks, которая написана на C и летала при этом в космос. А может что-то работающее вообще bare metal, там тоже C и ассемблер.

      Я пока еще не видел bare metal кода на расте, может конечно он где и есть...

      FPGA тоже запретите в ответственной элетронике?

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


    1. unreal_undead2
      23.10.2024 09:44

      В эпоху многоядерных процессоров мало кто может показать многопоточный код на Си за который было бы не стыдно.

      OpenMP и на C и на Фортране даёт возможность использовать многоядерные процессоры (включая ядра на GPU) вполне цивилизованно.


  1. DieSlogan
    23.10.2024 09:44

    Писал и знаю Си, но новый проект начну на Rust-е.

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


    1. robert_ayrapetyan
      23.10.2024 09:44

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


      1. DieSlogan
        23.10.2024 09:44

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


        1. BoldDwarf
          23.10.2024 09:44

          Так в этом то и проблема.

          Если архитектура приложения построена правильно, то и хаки не нужны.

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


          1. DieSlogan
            23.10.2024 09:44

            Не согласен полностью. Архитектуру не напишет, но творить откровенную дичь всё на порядки сложнее.


            1. unreal_undead2
              23.10.2024 09:44

              "Настоящий программист напишет фортрановскую программу на любом языке" )


            1. arseniiv Автор
              23.10.2024 09:44

              Что Вами понимается под "откровенной дичью"?

              Не подумайте, что я пытаюсь выдивгать какие-то аргументы против Rust, но пока аргуементы в сторону безопасности выглядят весьма слабо, предполагая, что уже есть знания и опыт в С(т.е. понимание чего лучше не делать определенно). Кстати, просто желание попробовать себя в новом языке - это вполне аргумент.


              1. DieSlogan
                23.10.2024 09:44

                Под дичью я понимаю:

                • Создание двустороннего внутреннего сокета, один конец которого отдаётся callback-у, слушающего открытые соединения, на второй конец навешивается callback обработки, но помимо этого сокет передаётся потоку, который непрерывно читает из него. Данные вычитываются, анализируются и потом частично записываются обратно,чтобы их успел подхватить callback. (Если что, это я в прод. системе увидел, она уже 25 лет на рынке)

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

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

                • Создание святого объекта-контекста, который хранит ссылки на всё, что создавалось в программе, все важные переменные, все контексты. И передавать его практически каждой функции, вместо отдельных аргументов. Ведь так же проще.

                • Написание своих кривых/косых логеров, функций работы со строками, с датами, thread pools, вместо использования стандартных библиотек

                • Неявная проверка результатов функции, например функция возвращает значение по принципу strstr, и пишут if(!pseudo_str(val))

                • Получение const указателя и попытка записи в него. Ошибка довольно очевидная, но выявляется в рантайме

                • Макросы буквально на всё. На логгирование названия функции в её начале, на if(!val), попытка сделать укороченный тернарный оператор, на всё. Весь код из макросов.

                Разумеется, я понимаю, что от половины не убережешься. Но на Rust-е, как миниммум пишешь меньше кода. Какие-то вложенные структуры создавать и инициализировать проще и нагляднее.


                1. arseniiv Автор
                  23.10.2024 09:44

                  Первый случай настолько мудреный, что я не представляю где нужна такая конструкция. Но это опять же вопрос к тому кто писал, а не к языку

                  2,3 - ну это скорее непонимание того как это все работает в С

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

                  По всему списку, в итоге, вопросы к знаниям и навыкам того, кто создает конкретный код, а не к языку.


                  1. DieSlogan
                    23.10.2024 09:44

                    Первый случай, это веб-сервер event driven. Ну вообще нормально, когда приложение между потоками обменивается через сокет на callback. Пока ничего не происходит, то и процессор не жрёт. Но вот зачем в эту формулу добавлять ещё один поток с чтением, для меня загадка.

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


                    1. arseniiv Автор
                      23.10.2024 09:44

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

                      Да, я именно об этом.

                      Я когда-то очень давно (полагаю, что это было начало 2013 года), попал на JavaDay. Ну как...Начальник сказал записаться и пойти в порядке саморазвития. В общем, докладчик был из Одноклассников и рассказывал как они стартовали, как развивался код. Но поворотной точкой стал их выбор в сторону использованися Unsafe. Получается , рано или поздно все равно надо будет писать что-то что выходит за грани отведенной песочницы?

                      N.B. Я тут вспомнил из опыта, помогал одному предприятию апгрейдить ядро сети, и пока сотрудничал с ними, познакомился немного с внутренними их процессами, заодно познакомился с их программистом. Это был странный человек, который для внутренней информационной системы написал сам БД на php(!) и очень гордился этим. А интерфейс к этой системе писал тоже он. Интерфейс был так им "разработан", что обращался к бэкэнду довольно часто. В итоге имелась ситуация, что людям, которые работают с этой ИС запрещалось держать несколько окон открытыми, иначе происходило одно из двух - или браузер выжирал всю память или нагрузка на эту самую наколеночную БД сильно возрастала. Я не буду дальше продолжать список этой дичи, но я понял, что писать дичь в коде - это минимум того, что можно представить. Можно реализовывать дикие проекты с дичайшими нарушениями всех мыслимых рамок.


  1. andres1
    23.10.2024 09:44

    Пока живы микроконтроллеры будет жив и С в чистом виде. А значит ещё попишем на нём, родимом.


    1. unreal_undead2
      23.10.2024 09:44

      rust туда не заходит?


      1. andres1
        23.10.2024 09:44

        Туда даже плюсы не заходят. Надо иметь быстрый код, да ещё размерность переменных объявлять.


        1. unreal_undead2
          23.10.2024 09:44

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


          1. arseniiv Автор
            23.10.2024 09:44

            Вряд ли сейчас кто-то может предсказать будущее этой затеи. Надо смотреть на то, что дальше будет происходить с этой инициативой.


          1. andres1
            23.10.2024 09:44

            Так в микроконтроллерах ядро - только процессорное. А операционка там плохо приживается.


            1. DieSlogan
              23.10.2024 09:44

              Семейство RTOS операционок. FreeRTOS, Zephyr RTOS и т.п.

              Линукс, да. Тяжеловат.


            1. unreal_undead2
              23.10.2024 09:44

              Когда мы пишем само ядро операционки, её тоже фактически нет. Так что если можно писать ядро - можно писать и произвольный код. который бежит на голом железе.


          1. DieSlogan
            23.10.2024 09:44

            Знаю на ESP32, там Rust есть в двух вариантах: со стандартной библиотекой и без оной. В последнем случае у нас нет многих вещей, но это для тех контроллеров, где совсем мало места. ESP32 таким не отличается.

            К слову, под ESP32 есть множество библиотек Arduino, что требует установки оверхеда прослойки — Arduino Core на эти контроллеры. Вдобавок, можно писать на C++, на них и написано большинство библиотек.