Pull to refresh

Comments 56

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

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

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

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

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

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

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

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

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

mvnrepository, pypi, npmjs активно используются и в серьезных.

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

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

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

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

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

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

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

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

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

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

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

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

Если заменить на 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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Да, у Раста есть поддержка работы на "чистом железе", ей довольно серьёзное внимание уделяется.

Подробно всё написано в The Embedded Rust Book

Плюсы туда заходят. Но вопрос как использовать.

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

Sign up to leave a comment.

Articles