Комментарии 277
Есть множество причин, по которым нам нужно заменить C, а основная причина того, что это не было сделано раньше — отсутствие внимания к этой теме и недостаток подходящих инструментов.
Основная причина отсутствие внимания к этой теме? Странно. А может отсутствие внимание и говорит как раз в защиту C! Кто мешает разрабатывать языки? Никто и ничто, разрабатывайте на здоровье. А время покажет станет кто-нибудь из них достойной заменой C.
Это Штирлиц. Сейсас будет драка.
За что вы, прикладники, так не любите С? Ведь вы на нем не пишите. Почему Вы считаете себя в праве ограничивать системщиков в выборе подходящих инструментов? Давайте еще и ассемблер отменим. Он вообще ни разу не кроссплатформенный язык да еще и с типизацией куда как более строгой, чем в том же C.
Язык C жив до сих пор, потому что в своей области он самый удобный. Везде, где он был неудобен его уже заменили. Но код, непосредственно работающий на железе… Ну пусть пробуют. С прост в освоении и понимании. И, самое главное, самодостаточен. Libc и Posix в общем случае даже знать не надо чтобы писать код для микроконтроллера или процессора (будь то DSP или процессор общего назначения). Кросплатформенный ассемблер. И это ровно тот инструмент, который нужен разработчику. Просто не мешайте работать.
Инструмент вытащили далеко за области его применимости, и обнаружили — внезапно! — что он там плохо работает. И решили его заменить. Ну, да, писать либу размера и функциональности как OpenSSL на С — так себе начинание. Насчёт ядра Linux, например, уже нельзя сказать так уверенно. А что-то, что работает без ОС, "оживить" с помощью С — самое то.
Но ведь это нюансы, о которых мало кто думает. У меня многие знакомые программисты при слове "программировать" не вспоминают embedded даже с подсказкой. Типа "на железках дрова сами заводятся, как мыши в сене".
Нет, это не Штирлиц!
Хм. Ошибка выжившего?
Да ладно! А может наоборот — обилие CVE просто потому что код доступен для анализа и сделаны «best practice»? И стало просто отслеживать. Для остальных языков просто пока нет такого инструментария? Так это только вопрос времени…
P.S. Минус не мой, если что. Может ваше мнение и неверное — но и мое в общем не более чем экспертная оценка, ни на чем более не основано.
Да нет же — это точно был Штирлиц!
А никто не может. И вообще людям свойственно ошибаться. А так как и код, и компиляторы пишут люди — ошибки неизбежны. У меня нет ни малейших сомнений в том, что рано или поздно они обнаружатся и в коде на Rust (и, весьма вероятно, в самом компиляторе или runtime-библиотеке). По другому не бывает. К этому надо просто спокойно относиться.
Для меня С основной инструмент. И используется он именно в самой низкоуровневой части. И Linux'овой, и FreeRTOS'ной и просто прямо по железу. Я так скажу — сегодня альтернатив ему нет. Нишевые задачи имеют нишевые решения, но пока только С обеспечивает возможность писать относительно быстрый, относительно безопасный, относительно переносимый и относительно хорошо поддерживаемый в будущем низкоуровневый код одновременно. Остальное компромися с явными перекосами в ту или иную сторону.
Нападки на него не новы. Пока выдерживает. А что до минусов — обычная история. Да, здесь в основном специалисты по «бизнес-логике приложений». Понятно, что нота ДО (С а буквенной записи) вызывает у них священный трепет, граничащий с непониманием. А количество ошибок с их колокольни говорит о проблемах языка. Их право. Но посмотрим что будет, когда их языки получат кодовую базу C. Я тоже человек и тоже могу быть не прав.
Знаете в чём проблема языка С? Что он близок к железу и если ты не знаешь как железо работает, то твой код ПОТЕНЦИАЛЬНО уязвимый. Многие современные языки пытаются быть дружелюным и прощать ошибки, но если в С/С++ ты накосячить с указателями тебе никто об этом не скажет ибо это всё работает и имеет какую-то логику.
Даже можно поразвлекаться.
Возьми вебмакаку которая никогда не трогала железо и посади её писать программы под DOS на ассемблере и ты узнаешь что никто не понимает как работает железо, будет кучу говнокода и копипаста ибо а как?
Тоже самое с FPGA, многие кто приходят кодить под это просто не могут понять что САПР просто выкинет его код на этапе компиляции и не скажет об этом если он не правильный.
А код без багов пишут только программеры-ангелочки в небесном ВЦ. Под ласковым взором главного тимлида. Остальные смертные всегда пишут с багами. Увы, не до всех эта простая истинна доходит.
Просто чтоб писать на С нужно знать железо, а когда пишешь на иных языках то просто описываешь алгоритм. В этом и всё проблемы "Кококо С ужасный язык", просто иная область применимости и всё.
Проще говоря, это как сравнить С с питоном. На питоне ты просто описал алгоритм анализа и он работает, а на С будь добр не забудь память контролировать и использовать определённые подходы в проектировании, чтоб переполнение и багов не получить.
Суть лишь в том что сейчас уже никто не работает с железом напрямую, я даже не видел ни одного программиста что бы использовал "гото" хотя с ним компилируемый код в местах становиться на пару сотен тактов быстрее, что бывает крайне критично. А кто нить пользуется "? :"? Это в любом случае генерит инструкцию условного присвоения что впринципе не влияет на производительность. Или может кто-то из кодеров использует дерективы компилятора чтоб "флоаты быстрее считались"?
Я не видел никого. Обычно все просто описывали алгоритмы на С, и в этом плане он уже старый.
Просто чтоб писать на С нужно знать железо, а когда пишешь на иных языках то просто описываешь алгоритмчтобы писать на си нужно знать стандарт языка си. Программа, корректная с точки зрения стандарта и алгоритма, обязана корректно исполняться на любом железе, с поправкой конечно же на редкие баги компилятора и стдлибы. Си не просто так называют «кроссплатформенным ассемблером» — код на нем в первую очередь переносимый, а уже потом низкоуровневый. А если вы пишете не переносимый код, работающий только на конкретной железке, то вы просто закладываете себе больше проблем на будущее.
Ну я рад за вас что вы используете всё это, но я плаваю среди джунов и немного мидлов и там это всё редко юзается…
Я вообще писал на С только под одну платформу раньше и только недавно перешёл на компухтеры, ткчт без обид)
А на счёт кэша и TLB это 5 с половиной инструкций(шучу) где единственное доступное с ринга пользователя ток кэш. И там почти нету настроек а обычно что-то Типо "флаш кэш" и всё. Интриксы и вставки как раз оно
Ну и на счёт векторных инструкций всё неоднозначно, они вроде и нужны но и не нужны одновременно, тут трудно чего-то сказать
Хотя учитывают тенденцию что разница между 5МБ чистых бинарников и 1МБ не столь важна, то думаю да, С тут сосёт неплохо
Ну и про странный аргумент, он не в пользу кого-либо, а просто показывает разницу. Хочешь ручками оптимизировать, на те С, хочешь отдаться 4омпилятору и проч используй другие языки. Так я считаю
Нет, C и плюсы не дают максимальной производительности.А никто не дает, только остальные еще хуже
Ну тип, не всё можно запихнуть в вектора, да и ещё сами векторные инструкции ни без выкрутасов. В районе шуточки что нужно MMX/SSE/AVX и у них разная нагрузка на конвейер, частоты работы и ширина команд. Вам какие вектора)?
Ну вообще я понял почему на лурке написано — "С/С++ ужасный и (вроде) новый функционал строиться на костылях, но увы ничего лучше ещё не придумали"
+о себе скажу что привык к verilog и не умею в "абстракции", мб потому пока ещё не наткнулся на проблемы в этом языке. Хотя работа с ссылками меня откровенно бесит… Ты просто указатель на память со сдвигом так почему я должен тасовать эти типы и писать кучу кода, капеец)))
Более того, С скрывает даже наличие векторных инструкций, и приходится либо использовать интринсики, либо ассемблерные вставки.
Слушайте, хап хайпом… Но вот. Впрочем, это уже плюсы. Это уже специализированный компилятор под фиксированную платформу (ради пиковой производительности). Но уникальная задача всегда требует уникального решения. Велика сила С(++) ровно в том, что он способен выдать это самое уникальное решение для уникальной задачи. В остальных случаях оставаясь переносимым и достаточно производительным.
Вообще, никто и никогда не запрещает кодогенератору языка С использовать эти инструкции. Не делает он это отнюдь не потому что не может. Вспомните сколько вою было когда i386 убрали из поддерживаемых архитектур и сказали что теперь i686 минимум. Да и той уже нет. Потому 32-разрядные ARM'ы планомерно превращаются в тыкву следом за десктопными компьютерами. А прикладные программисты, радеющие за прямой доступ к векторным инструкциям и доступом к состоянию кеша… На фол последней надежды в футболе смахивает.
Что ж до «goto» и оператора "?", то по сути это вопрос стиля. И в целом тут не важно какой стиль использовать, важно не смешивать их друг с другом. Как минимум без крайней на то нужды. В случае «goto» и "?" это возможность избавится от лишних ступенек в идейно линейном коде. В этом смысле они хороши. И вполне себе используются. Впрочем, опять же — до понимания плюсов этих операторов надо дожить.
И конечно и безусловно — С (как и любой другой язык) невозможно выучить за 21 день. А предела совершенству нет. Потому чем дольше «точишь» мастерство, тем больше тонкостей применения тебе открывается. Другое дело, что желающих «точить мастерство» остается все меньше и меньше. В мире реальных вещей ценность «ручной работы» опущена ниже плинтуса. Это статусные и брендовые вещи. Пробраться в тот круг начав сегодня практически невозможно. В лучшем случае «сливки» снимут внуки. И то, если «дети» продолжат начато отцом. В программировании пока чуть лучше. Однажды созданная «цифровая» вещь дальше размножается методом почкования с минимальными затратами. Потому здесь еще эпизодически рождаются «штучные» вещи, которые выглядят реально классно на фоне «фабричных» аналогов.
В этом смысле С ушёл. Условному Mediatek нужно буквально пяток сотрудников для того чтобы создать U-Boot под свой новый условный Helio. И еще пяток для того чтоб адаптировать ядро. Все. 10 специалистов по низкоуровневому программированию обеспечат работой тысячи (если не десятки тысяч) прикладников. Начиная с условного Google (Android, PlayMarket, etc...) заканчивая авторами приложений и инди игр (а еще обеспечит работой всяких Youtube- и TikTok- блогеров). Странный парадокс в том, что эти «тысячи и десятки тысяч» разработчиков упорно учат тот самый десяток тому, что С плох и недостоин носить гордое звание языка программирования и вообще скоро умрет. Ну как тут не вспомнить знаменитое «миллионы не могут ошибаться»
Велика сила С(++) ровно в том, что он способен выдать это самое уникальное решение для уникальной задачи.
Это самое "уникальное решение" можно сделать на любом языке, позволяющем использовать ассемблер. То есть на почти любом языке.
Вообще, никто и никогда не запрещает кодогенератору языка С использовать эти инструкции. Не делает он это отнюдь не потому что не может.
В случае с char*
— именно что не может, потому что указатели на char
могут алиаситься с любыми другими указателями.
Потому 32-разрядные ARM'ы планомерно превращаются в тыкву следом за десктопными компьютерами.
Как это следует из ваших слов?
Что ж до «goto» и оператора "?", то по сути это вопрос стиля.
Это не вопрос стиля, это вопрос лёгкости анализа кода, причём как статическими анализаторами. так и людьми.
В случае «goto» и "?" это возможность избавится от лишних ступенек в идейно линейном коде.
От лишних ступенек с ветвлениями избавляет оператор if
, являющийся выражением. Но для C это, конечно, слишком сложно и революционно. Тернарный оператор не только плохо читается, но и ведёт к багам, потому что в C у него крайне неинтуитивный приоритет (в статьях той же PVS-Studio показывалось неоднократно, что это баги таки вызывало). Использование же goto
в сишном коде — это либо хреновая замена break
/continue
, либо замена условных операторов для очистки выделенных ресурсов. В более продвинутых языках задача освобождения ресурсов возложена либо на деструкторы, либо на сборщик мусора и using
/with
/defer
. И даже в C для этого есть GCC-изм attrubute((cleeanup)). Использование голого goto
практически никогда не оправдано.
И конечно и безусловно — С (как и любой другой язык) невозможно выучить за 21 день. А предела совершенству нет. Потому чем дольше «точишь» мастерство, тем больше тонкостей применения тебе открывается.
Но в других языках как-то получается учить язык без изучения всё новых способов выстрелить себе в ногу.
Другое дело, что желающих «точить мастерство» остается все меньше и меньше.
Всё больше людей хотят просто программировать и при этом не держать в голове сотни условий, при которых происходит UB. Ну надо же!
В мире реальных вещей ценность «ручной работы» опущена ниже плинтуса. Это статусные и брендовые вещи.
Так ниже плинтуса или статусные?
В этом смысле С ушёл. Условному Mediatek нужно буквально пяток сотрудников для того чтобы создать U-Boot под свой новый условный Helio. И еще пяток для того чтоб адаптировать ядро.
Или условно два сотрудника с использованием условного Rust.
10 специалистов по низкоуровневому программированию обеспечат работой тысячи (если не десятки тысяч) прикладников.
Напомните, сколько людей пилит компиляторы, без которых тот же U-Boot нахрен никому не сдался? Кажется, больше 10 человек. Сильно больше.
Странный парадокс в том, что эти «тысячи и десятки тысяч» разработчиков упорно учат тот самый десяток тому, что С плох и недостоин носить гордое звание языка программирования и вообще скоро умрет. Ну как тут не вспомнить знаменитое «миллионы не могут ошибаться»
Если вы всерьёз считаете C хорошим языком, то вы достойны всяческого порицания. Популярность C для низкоуровневого программирования — следствие более исторической случайности, нежели каких-то преимуществ C. И да, C нихрена не простой.
Но в других языках как-то получается учить язык без изучения всё новых способов выстрелить себе в ногу.
А теперь (только предельно честно) — как давно вы учили новый язык? Изучение любого языка начинается с отстреливания себе в ног и рук. И хорошо как ими ограничивается. Ибо чаще всего ломается мозг. А вот починить его до конца практически никогда не возможно. Потому и есть «профессиональная деформация» в связи с используемым языком.
Всё больше людей хотят просто программировать и при этом не держать в голове сотни условий...
Надо же. А меня-то учили, что любую задачу сначала должен решить программист в уме. Потом изложить методику ее решения на ПОНЯТНОМ МАШИНЕ языке и удостовериться в том, что машина ее решает верно в независимости от входных данных. Конечно, все больше людей хотят гребсти бабло лопатой корча из себя "великих программистов" (что бы это не значило). Только не надо в сложившейся ситуации винить язык.
Или условно два сотрудника с использованием условного Rust.
У вас есть машина времени? И как там в никогда? Нефть тоже вообще нигде не используется? Подшипники в электромобилях смазываются непосредственно электричеством? Или в вашем никогда повсеместно магнитная левитация и энергия исключительно из солнечных батарей? Пластики не используются? Деревья сразу вырастают в виде нужных компонентов?
Напомните, сколько людей пилит компиляторы, без которых тот же U-Boot нахрен никому не сдался
К проблеме курицы и яйца в компьютерах подход простой. Кто ближе к розетке того и тапки. U-Boot ближе.
Если вы всерьёз считаете C хорошим языком, то вы достойны всяческого порицания.
Так единственное о чем я прошу — не мешайте мне страдать. Это реально все.
P.S.
И да, C нихрена не простой.
Как говорит мой отец — просто с моста прыгнуть. Головой вниз. Над остальным надо работать.
Почему-то ноги целы и на месте.
А вы точно учили язык и продвинулись дальше «hello world»? Perl, TCL, VHDL, Verilog, Rust, да тот же Python мне изрядно попортили конечности. Правда все они были отложены ровно в тот момент, когда они добрались до мозга. Ибо ну его нафиг — меня кормит «хронический С головного мозга» и мне категорически нельзя допускать внеплановых «обRust'рений» других болезней.
Это работает только для тех задач, которые помещаются в уме.
Да ладно. А все методики типа сверху-вниз, ООП и прочее уже отменили?
То есть, когда я под AVR'ки писал, я был ближе (или круче, или фундаментальнее), чем gcc, которым я собирал свой код? Прикольно.
М… А вы компилятор потом непосредственно на AVR'ке запускали? Тогда да — круты и не слабы. Снимаю шляпу.
Так разговор ведь о том, что C оказывается в основании стека, поэтому ваши страдания тоже влияют на других людей.
Думаете? А мне кажется, что люди в подавляющем большинстве случаев страдают по другим причинам. Только смелости объективно признать те причины и начать с ними бороться у людей не хватает. Поэтому свалить по привычке все на соседа оставив себя белым и пушистым сильно проще.
Жду… Сильно жду, когда наконец хоть кто-то из страдальцев начнет исправлять ту самую ситуацию когда С в основании стека технологий. Вот, тот же CodeRush (да, магия хабра специально не применена) говорит — тошнит от С, но переписывать UEFI на Rust никто не хочет. Почему? Потому как экономически (пока?) не выгодно. А в качестве pet-проекта… Хороший специалист по работе загружен так, что в качестве pet-проекта у него самый настоящий pet. И никак иначе. Потому бурлим. И пена идет. Но подождем пока все это доварится. Тогда и будем пробовать получившееся блюдо на вкус.
Потому бурлим. И пена идет. Но подождем пока все это доварится. Тогда и будем пробовать получившееся блюдо на вкус.
Когда вам станут очевидны преимущества Rust, поезд уже уйдёт.
Но в этом случае я не решаю задачу в уме! В этом случае я её решаю итеративно: сначала делаю первый набросок, потом заполняю детали, потом ещё…
И что ж это такое, как не разработка методом сверху вниз? Декомпозиция задачи — один из основных навыков программиста. И при этом она все равно сначала решается в уме (пусть и частями, а не вся сразу). О чем спор-то? Или вы серьезно считаете, что тот же Линус держит в голове все последовательность инициализации ядра на всех платформах?
И да, простите. Мне крайне сложно оценить наcколько «Hello, world!» код в вашем репозитарии. Потому просто верю.
Другое дело, что инструменты, которыми пользуетесь Вы реально помогают с математической точностью доказать стабильность решения. И как всегда — вопрос цены. Цены разработки инструмента, цены разработки и сопровождения. Вы же прекрасно понимаете — как только эта цена превысит цену ошибки, так сразу эти решения начнут внедрятся повсеместно. Пока подобное произошло (?) в привычных вам финансовых сферах. Но надо ж понимать, что никакое решение обычно не является универсальным.
Но я сужу по знакомым, которые страдают от дыр в openssl, в ядре линукса, и так далее.
Если человек страдает, но не предпринимает мер для устранения источника страдания, то он или мазохист или… страдания ничтожны в сравнении с получаемым удовольствием. Ту самую OpenSSL переписали на Rust. Вроде даже работает. Верю — народ страдал. А про ядро… Так мне уже сказали — очень толсто.
Математически выверенный устойчивый код на контроллерах. Ну да, за этим будущее. Только до этого будущего еще большой путь. Сначала должен появиться инструментарий и реальные требования для контроллеров ответственной сферы. Космос, медицина, энергетика, транспорт… Потом, когда оно докажет свою целесообразность и состоятельность — промышленность и малая автоматизация. И только после этого всякие домашние поделки типа ардуино и прочих конструкторов.
Я же не имею ничего против эволюции. Я против революции. Когда пусть и хорошее решение, но навязывается «огнем и мечом». Впрочем, помня возрастной срез аудитории хабра не удивительно что здесь как раз сторонники революционных мер. «До основания, а затем. Мы наш, мы новый мир постоим.» Только вот не дам я «до основания» раньше, чем другой мир появится. И, к счастью, не только я.
Не начинает решать, а решает. Целиком. «Решить» — совершенная форма.
И все же здесь я вынужден настаивать на своей формулировке. Именно решить. Именно совершенная форма. Весь верхний (а лучше несколько верхних) слоев если мы говорим о сверху-вниз.
Только этот путь не пройдётся сам, его надо активно проходить.
Так я ж не предлагаю стоять на месте или двигаться назад. Я с интересом наблюдаю за развитием того же Rast'а. Вопрос в том, что подавляющее большинство собеседников похожи на моего старшего сына. Тот тоже подходит с вопросом «папа, а давай сделаем...» подразумевая «папа сделай, а я в лучшем случае рядом постою». Во всяком случае когда дело касается системного программирования. А уж как хотите — возглавлять крестовый поход против С я точно не буду. Пока есть заказчики на код на С (создание, поддержка) я буду писать на нем. Ибо это тот инструмент, навык пользования которым я точил и продолжаю точить. Вот не будет — тогда буду думать. И то, скорее о гидропонной ферме и прудике с карпами в деревне, чем об освоении чего-то диаметрально отличающегося.
Почему всё? Только проверку того, что они правы.
Хорошо, а что остается от того все?
Хотя лично у меня нередко бывает exploratory programming, когда я не до конца понимаю проблему, и открываю редактор и начинаю что-то в нём писать-играться, чтобы лучше эту самую проблему понять.
Подход художника vs подход скульптора. Под многими даже очень известными картинами реставраторы находят второй и временами даже третий слой. Начал рисовать. Не понравилось. Закрасил и переделал. Некоторые картины вообще откровенно поверх неудачных работ написаны. Скульптору так нельзя. Уж если отколол, то отколол.
Уверены что скульптора камнетеса хотите заменить на 3D-принтеры просто потому что у тех возможности «накосячить» меньше и повторяемость результата лучше? Мало того — молото с зубилом запретить, скульптуру объявить лженаукой и изгнать из учебных заведений? Есть же море альтернатив. Литье, ковка, лепка, рисование, те же 3D принтеры.
Построение решения задачи.
Почти убедили. Остался один момент — а есть уверенность, что ответственную задачу можно поручать троечнику, который с трудом понимает граничные для нее условия? Или что не еще хуже понимает, но не знает как обойтись без «умной машины», которая за него все посчитает?
Отличная аналогия! Никто вас за язык не тянул :]
Превосходно. Только настоящий инженер сначала эскиз рисует. И до реально «железного» изделия обычно бывает множество прототипов. Потому как изделие (особенно тщательно обсчитанное, из выверенного материала, с проверкой на полости и пустоты) стоит денег. Да и в массы оно идет уже не литьем, а ковкой, гибкой, фрезерованием (что мало отличается от скульптуры) и имеет очень много расхождений с первым высчитанным экземпляром. И изделия все равно (как минимум выборочно) проходят натурные испытания.
Да, конечно, механика не IT. Детали не размножаются простым копированием. Но если деталь можно сделать ковкой или вырезкой — будьте уверенны никто ее не будет печать на 3D принтере.
Про «не скульпторов зовут». Есть такая профессия — макетчик. Это специалист по деланию МАКЕТА изделия из любимых подручных материалов. Кабели — веревки, корпуса — моченые газеты, мелкие детали — пластилин. Незаменимый человек на начальном этапе — проектирования. Когда эмоции бурлят, у каждого свое видение готового изделия. И надо сравнить разные варианты и выбрать самый удобный. И уж только с него инженер начинает что-то считать. А еще с него можно начать готовить кофры, чехлы, встраивать куда-то. Если все это делать 3D принтером то никуда не успеешь и денег не напасешься. Даже автомобили делают из макетной глины. Да и массовое производство… Впрочем, я про него уже писал.
Так что не надо мне рассказывать про идеальный мир, сделанный инженерами в SolidWorks. Как и про идеальный мир, где все вообще написано на абсолютно безопасных языках. Я, знаете ли, не хочу чтоб меня «умная дверь» из дома не выпускала на том лишь основании, что без ее надзора я прямо в коридоре споткнусь и коленку расшибу.
Тогда к чему вы вспомнили про 3D-принтеры?
Так все же просто. Всегда есть два подхода. Взять заготовку и отсечь все лишнее и взять ничего и «слепить» нечто. До сих пор в основном главенствовал (и главенствует) первый. Но хайп вокруг вторых приводит к тому, что они начинаю применяться где только можно. Местами сильно мешаясь и наоборот замедляя работу. Макет из папье-маше опытный макетчик сделает быстрее и точнее чем 3D распечатает 3D принтер. Часть задач на С надежно решить получится быстрее и не менее качественно, чем описывать ради этого все особенности преобразования типов в них на том жe Rust'е. Я бунтую против Вашего «требую чтоб везде». Я не бунтую против инструментов.
А можно я всё же буду?
Можно. Только получите в ответ провокационный вопрос. А на чем написан SolidWorks? Как вам может нравиться код, написанный на «рассово не чистых» языках?
И потом. В расчетных библиотеках того же Solid'а встречаются ошибки. И ни одна сертификационная лаборатория не поставит штампик только на основании того, что мы «посчитали в Solid'е». А если конечное решение все равно за сертифицирующим центром, то зачем навязывать всем именно Solid. Есть альтернативы. AutoCAD, тот же Компас, кульман в конце-концов. Почему вы считаете себя в праве ограничивать разработчика в выборе инструмента? Более того — вот уже вторую неделю упорно доказывать правоту такого подхода? Ведь весь сыр бор исключительно по этой причине. Или личная неприязнь и предвзятое мнение непосредственно к языку С.
Это очень сомнительный для меня тезис, но не думаю, что его обсуждение будет конструктивным.
Можно подумать во всем этом обсуждении есть хоть один не сомнительный тезис. Да и в целом обсуждение конструктивностью не блещет. И это было просто очевидно с самого начала.
Мы же не обсуждаем, на чём написаны coq, agda или idris?
Значит ядро и драйвера осуждаем, а остальное нет. Впрочем, да — конструктивности тут ждать не приходится.
Если этот опытный макетчик стоит как стопицот 3D-принтеров, то его услуги будут не очень востребованы.
Это полит-экономический вопрос. Инженеры их (обычно) сторонятся. Впрочем, имею честь наблюдать результат Solid + 3D принтер сейчас vs приходящий макетчик + дизайнер за кульманом некоторое время назад. Я не конструктор. Но меня всегда зовут на обсуждения конструктивов изделия (причины вынесем за скобки, сказав для простоты что доверяют моему инженерному чутью). Так вот — корпус на принтере получается реально красивым только чистовой. Очень долго и очень дорого. Оперативные корпуса… Нет, «бумажные» однозначно были лучше. И уж точно по совокупности не дороже. А те наработки используются до сих пор, незначительно дотачиваясь под современные. Не родило поколение фанатов 3D принтеров ничего принципиально нового. Впрочем… Возможно их полет фантазии просто сдерживали… И как раз последствия пандемии наконец смогут помочь им показать себя во всей красе… Не ругаю я коллег. А уж тех, с которыми работаю и подавно.
Впрочем, есть свои плюсы у печатных. На них проще оценить финальную конструкцию. Реальные платы, разъемы, дисплей, шлейфы… Тут не так важна кривость корпуса, как четкое понимание — состыкуются компоненты или нет. Будет шлейф перекручен или нет. Есть необходимые зазоры или упираемся. Но все равно — будь решение за мной я бы начинал с «бумаги».
Но блин — каждому инструменту свое применение. Это единственный конструктив из всей этой темы. Есть спрос на С — будет С. Нет спроса на С — будет что-то другое. Мне хватает заказчиков, которые не так сильно обеспокоены RCE и прочими неприятностями. Хотя… Не скажу что подход когда безопасность решения базируется лишь на том, что «противник не знает систему» мне нравится. И я всячески пытаюсь убедить таких заказчиков в том, что так нельзя. Но и фанатично вкачивать ресурсы в безопасность ради безопасности и неудобства пользования изделием… Так себе удовольствие.
Остался один момент — а есть уверенность, что ответственную задачу можно поручать троечнику, который с трудом понимает граничные для нее условия? Или что не еще хуже понимает, но не знает как обойтись без «умной машины», которая за него все посчитает?Так а вы что бы выбрали, поручить такую задачу:
— троечнику + стреляющий по ногам ЯП;
— троечнику + безопасный ЯП?
Детский сад право слово.
Специалисту тотальный контроль не нужен, и даже вреден. А троечников просто до ответственного кода допускать нельзя. Сертификация, обучение, аудит кода, тестирование всех мастей — что угодно. Но не снижение планки подготовки разработчиков.
Впрочем, успокойтесь вы уже. Я же сказал — OpenSSL на здоровье. Пусть хоть двоечники переписывают. Нет тут особых требований по скорости — безопасность перевешивает. И себе выбирайте язык, который вам комфортнее. И забирайте от меня часть работы.
Пока ваши крики сказочку про Петю и волка напоминают. Слишком уж мрачную картину нарисовали.
Страшно за то, что вместо собственного развития и понимания они готовы отдать все на откуп машине.
Скажите, а вы спеллчекером пользуетесь?
Видимо, да. Вы предлагаете, условно говоря, программистам "просто" писать без опечаток вместо того, чтобы использовать спеллчекер.
Но в целом идея именно такая. Spell check — это компилятор, а уж meaning checks — это строго за человеком. Во всяком случае в тех местах, где производительность не перевешивается безопасностью (хоть safety, хоть security).
Популярность C для низкоуровневого программирования — следствие более исторической случайности, нежели каких-то преимуществ C.Wtf?
А что, есть реальный выбор для эмбеддед, ну хотя бы сейчас?
Ну и исторический взгляд тоже не помешает. На момент создания С +- 5лет
P.S Или может в области ядер операционных систем случился какой то прорыв, а я пропустил?
есть реальный выбор для эмбеддед, ну хотя бы сейчасПлюсы, Ада, Forth, подмножество Rust. Форт поменьше и пошустрее, Раст побольше и помедленнее, Ада с плюсами на уровне С.
Ну и исторический взгляд тоже не помешаетЕсли смотреть просто по списку, то выбор был: Forth, Simula, PL. А какая на самом деле была известность, доступность документации и эффективность работы компилятора — это у олдфагов надо спрашивать, кто застал.
Занесу тебя в игнор.
А если вы считаете этим ЯПом педеrust, то я вообще в шоке!
У вас как-то очень много отсылок к прикладным программистам с коннотациями, которые я не до конца улавливаю
Конечно. Потому как прикладное программирование много шире системного. Потому нет к нему единого отношения. Однако, в подавляющем большинстве случаев для прикладного ПО характерен ответ в стиле «Подумаешь тормозит! Завтра будет новое поколение процессоров и еще больше памяти и будет летать.» Именно этот ответ я получил в ответ на недоумение от факта запуска на Marvell PXA320 с носителем в виде SD карточки под Linux postgreeSQL. Особый шик в том, что это самое «железо» для них делал я (тогда еще сам). И вполне себе отдавал отчет в том, что ни завтра, ни послезавтра я им не выкачу систему, которая на подобное способна. В любом случае системщики себе такое поведение позволить не могут вообще никогда. Собственно, если хорошо подумать, то именно возможность именно такого отношения к задаче делит мир на прикладников (тех, кто может) и системщиков (кто не может).
Точить мастерство листания и интерпретации стандарта, чтобы понимать, UB передо мной или не UB, можно ли код коммитить...
Знаете, вот это именно та часть по которой уже я не понимаю Вас. Временами мне кажется что я разговариваю не с разработчиком, а с предвзятым критиком. А с такими, как религиозными фанатиками…
… или я закладываю бомбу, которая может взорваться через пару апгрейдов компилятора ...
Слушайте, а мы точно про С сейчас говорим? В самом деле. Даже код 20-летней давности (за который немного стыдно) совершенно без проблем компилируется современными компиляторами и выдает рабочий бинарь. По сути это просто возвращает нас к тому самому моменту про оптимизатор. Не надо оставлять свободы оптимизатору и код останется рабочим навсегда. А умение так писать… Ну да, оно точится. И без фокусировки на инструменте (вместо расширения по фронтам и осваивания всего и вся) эта задача нерешаема.
Отчасти по этой причине я посмотрел на Rust и… отложил его в сторонку. На моей памяти С «воевал» с ассемблером не один десяток лет (попутно отбиваясь от Pascal'я и Basic'а). Вполне достаточно для жизни поколения разработчиков. Пусть молодые разработчики осваивает Rust. Возможно, действительно через некоторое время появится шикарная возможность сменить пяток наСильников на пару Rust'оманов.
К слову о реально важном. Ау, фанаты Rust! Фиг с ним с ядром — сделайте аналог U-Boot'а для Cortex-A. У этой задачи нет жестких требований по размеру, она не висит в памяти резидентно и весьма востребована. Ибо barabox тоже не сказать что совсем уж торт. У вас сегодня для этого все есть.
С -O0, небось? Новые компиляторы приносят новые оптимизации, основываясь на новых способах интерпретировать UB.
-O size для контроллеров. Для ПК у меня значимых абсолютно своих проектов нет, но насколько мне известно тот же Linux и U-Boot собирается отнюдь не -O 0.
Впрочем, для сборки ядра 2.6.35 нужен gcc не выше (не помню) и bunutils не выше (тоже не помню). Так что я не возьмусь утверждать, что в Ваших словах правды нет совсем. Но это тема уже другого разговора. Где тема недостатков языка С уже не будет иметь такой существенной роли.
Давайте я сначала сформулирую такой тезис, с которым, надеюсь, споров не будет...
Да ешкин же кот. Конечно. Безусловно. Абсолютно верно. И я разве где-нить выступал против?
«Вагонные споры последнее дело, когда больше нечего пить» (с) Макаревич
Причина ж не в этом. И спорим мы с вами не об этом. Ведь весь наш спор идет по сути вокруг одной простой идеи. Вы ратуете за то, что компилятор не должен позволять «говнокодить». Я ратую за то, что разработчик не должен позволять себе «говнокодить». Вы говорите раз компилятор позволяет разработчик обязательно наговнокодит. Я говорю что фантазия разработчика сильно шире и всегда найдутся индивидумы которые обойдут любые ограничения компилятора и все равно наговнокодят. Вы соглашаетесь и ратуете за усиление контроля со стороны компилятора. Я соглашаюсь и ратую за усиление воспитания программиста. И… Опять все сначала.
"… и каждый пошел своею дорогой, а поезд пошел своей." (с) Он же и там же.
Вы ратуете за то, что компилятор не должен позволять «говнокодить». Я ратую за то, что разработчик не должен позволять себе «говнокодить»Так в статье про то, каким должен быть хороший ЯП нельзя надеяться, что косяки языка будут компенсированы преподавателями computer science.
Я уже писал. Личное дело каждого в какого бога верить.
Несогласных со статьей расстреливают сразу?
Первой аксиоме учат в учебных заведениях (ну и жизнь тоже учит).
А второй должны следовать разработчики очередного ЯП.
То есть вы всегда сначала делаете, а потом думаете, почему так получилось?
Так кто из нас кричит, что С несовременная, дурно пахнущая субстанция требующая срочной замены повсеместно? Разве я?
Я 30 лет назад принял решение и стал электронщиком (схемотехником). С серьезным уклоном в цифровую технику. 20 лет назад понял, что схемотехник вот-вот переплюнет ювелира, а я никак не могу своими руками менять BGA чипы обычным паяльником (да и компоненты типоразмера 0201 мне уже не по силам). Потому переквалифицировался в программиста. Системного. Сначала Assembler, затем C. И до сих пор именно этими знаниями решаю те самые «бизнес-задачи» и «воплощаю требуемую логику» (что бы это не значило). Там где можно. А там где нельзя упорно отговариваю заказчика и уступаю место тем, кто по моему мнению с данной задачей справится лучше. Потому и говорю: «Считаете что можете заменить С в конкретном месте — меняйте. Нет — не [синоним слову говорите] и не мешайте работать.» С OpenSSL же получилось (получается?).
Да, я сначала думаю, потом делаю, потом снова думаю и снова делаю. И эта цепочка прерывается ровно в тот момент, когда заказчик говорит — достаточно. Результат меня устраивает.
Переформулируйте вопрос.
Переформулируйте вопросЯ думаю, что вы прекрасно сами все поняли. Вот только я одного не пойму, в чем вы упрекаете людей, которые хотят разобраться в преимуществах и недостатках конкретной технологии? А также в возможных альтернативных вариантах (которых может еще и нет).
С OpenSSL же получилось (получается?).отличный пример библиотеки, печально известной за обилие багов, использование которой вызывает PTSD у бывалых кодеров. Говорят кстати алгоритмы шифрования переписали на безопасном расте.
Далеко берёте...
Да просто вспомнилось. Впрочем, радетелям «правильных» языков могу порекомендовать собрать на Ubuntu 20.04 LTS хотя бы AOSP 9.0. И поплеваться с питона. Для меня это вполне свежий пример, показывающий что на определенном этапе развития языка подобные проблемы неизбежны.
для говнокодинга достаточно ограниченной внимательности.
О да. Этого всегда достаточно. Было. Есть. И будет. При чем чем больше доверия автоматике, тем больше. Именно по этой причине натурные тесты в критических и закритических условиях всегда крайне желательны (а в некоторых областях обязательны).
Железна дорога. Поезда не автомобили — благодаря железнодорожной автоматизации и автоматике трех состояний (включено-включено-неисправно) поезд способен передвигаться без участия машиниста. Но машинист все равно остается на месте. И сложными ритаулами всегда остается при внимании. Доклады. по радио, сигналы (гудки), кнопки — watcgdog'и. И все ради того, чтоб в критической ситуации машинист мог остановить работу автоматики (механически). При этом причина подавляющего большинства крушений все же человеческий фактор. Так вот — вместо автоматизации и убирания человека изобретаются все новые и новые возможности удерживать его внимание. Насколько мне известно, примерно похожая ситуация в авиации и морских перевозках (вне портов).
Ваша автоматическая проверка — это система автоведения. Да, она поднимет тревогу при обнаружении проблем. Да будет приставать при отсутствии нарушения, но возникновении потенциально опасной ситуации. Да, она оправдана в случае ответственных решений и все равно оставляет последнее слово за человеком.
Но… Запрещать на этом основании речные лодки (неустойчивые, требуют собранности и синхронизации рук), гироскутеры (скорость и внимание), велосипеды и моноколеса (ужас — мало того что руками рулятся, так еще и неустойчивые — кошмар то какой), всю малую авиацию (ужас — требуют собранности во все время полета). По моему вы просто хватили лишнего. Но категорически не хотите этого признавать.
Но… Запрещать на этом основании речные лодки (неустойчивые, требуют собранности и синхронизации рук), гироскутеры (скорость и внимание), велосипеды и моноколеса (ужас — мало того что руками рулятся, так еще и неустойчивые — кошмар то какой), всю малую авиацию (ужас — требуют собранности во все время полета). По моему вы просто хватили лишнего.
Лично я был бы тоже против, если бы на моноколёсах перевозили ядерные боеголовки, как это происходит сейчас.
И тренд на то, чтобы добавлять больше страхующих систем, а не удерживать внимание.
ASLR — да. Неисполнимый стек — да. Тотальный контроль — категорически нет.
Люди, которые ими пользуются, скорее себя угробят, чем других
Владельцы транспортных контор, в парке которых КАМАЗы (или в Вашем случае Freightliner) одобряют. Автобусы и такси тоже не представляют абсолютно никакой опасности для окружающих. А уж свободное хранение (а паче ношение) оружия — вообще абсолютно безопасное затея для окружающих.
Вам жить не страшно? Столько опасностей вокруг. Может в сравнении с ними очередное переполнение буфера в ядре просто безделица?
Вы, кстати, ведь в курсе, что ваши права по полётам сильно ограничены, если у вас нет ADS-B?
Я не знаток авиационных систем. Но в любом случае — это информационная система. Она не перехватывает управление полетом и не устраняет главную причину авиакатастороф. Да, я о человеке.
Поэтому есть такая тема… На получение license to carry надо сдать экзамен.
Хм… А ответственный код значит можно писать не имея на это право?
Люблю быть, знаете, хакером и исполнять всякое со своего стека.
Как вы говорите — да на здоровье. Как хобби или исскусство. И лучше спрятать в запасники музея для специалистов, чтоб не дай бог дети не увидели.
всё не нужно, если просто писать код аккуратно, без багов и дырок.
… или (что важнее) использовать код непосредственно для решения задачи. Возможность кода решать поставленную задачу — забота отдела качества и сертификационной лаборатории. Если это выполняется, то какие претензии к инструментам?
Другое дело, что в последнее время стало мало выполнять непосредственно задачу, поставленную перед кодом. Все эти хакеры, и прочие local privileges escalation и remote code execution… И вот это действительно проблема. И у меня нет хорошего пути решения для этой проблемы. Но мне кажется (больше того — я уверен) что решаться она должна не сменой инструмента, а повышением образованности разработчиков. Скорее всего это должно привести к тому, что сильно больше будет специализация разработчика, а популярные нынче варианты «сегодня AVR, завтра front-end, послезавтра Java» потихоньку должны умереть. Ибо именно это не что иное как анархия. В которой некоторое количество сообщений назад обвиняли меня и язык С.
Ну да. Александреску доточился и свалил в D. Мейерс доточился и свалил из индустрии вообще. Я, конечно, не Мейерс и уж тем более не Александреску, но я тоже доточился. Точить мастерство листания и интерпретации стандарта, чтобы понимать, UB передо мной или не UB, можно ли код коммитить, или я закладываю бомбу, которая может взорваться через пару апгрейдов компилятора, как-то стало всё меньше желания.Надо не путать между «доточился» и «сточился» [в попытках понять].
Насчет UB я вообще не понимаю. Практики делают как им надо, остальные ноют про УБ.
Здесь я вижу прямую аналогию с ПДД, когда новички ноют про сложность и непонимание, а остальные просто ездят с минимум проблем.
а я не согласен.
да, владение C можно улучшать бесконечно.
но «выучить» (понять как оно устроено) мне в подростковом возрасте хватило несколько дней чтения k&r. без практики (ибо не на чем было). потому что если знаешь ассемблер, то читаешь k&r и понимаешь почему было так сделано, а логичные вещи и изучаются легко.
примерная аналогия: если мы будем изучать биографию чемпиона мира по спортивной ходьбе и там будет написано «научился ходить XX.XX.XXXX», то мы ожидаем увидеть когда он сделал несколько первых шажков (пусть и упал после этого), а не когда он стал чемпионом.
… У которого обе грани заточены. И рукоятки нет. И оба конца острые...
Простите. Не смог удержаться.

Да, С именно такой. Только вот обматывать его тряпочкой, или резать лук… Не, ну можно конечно. Но лучше перерезать себе все руки, но наработать инстинкты безопасного поведения и перестать его бояться бояться и начать оттачивать умение им пользоваться.
На самом деле вопрос-то очень интересный. Я корнями в деревне. По детству, в самых дальних закоулках чердоков находил иконно русскую косу-горбушу. И даже доставал, точил и косить пробовал. Но старички смотрели, хмыкали и говорили — не майся ерундой. Вот тебе нормальная коса (коса литовка). И да, вот ее я освоил. В совершенстве. Площадь, обкосить вокруг кустов, неровная поверхность — все равно. Все будет обкошено. Да так, что травы останется ровно 1,5 сантиметра. Сегодня молодежи уже я хмыкаю и говорю не майтесь ерундой — есть же триммер. И да, триммер быстрее и удобнее. Усталости сильно меньше. Но сам почти всегда достаю привычную литовку. Как так? А вот так. Только ей у меня получается сделать хорошо. После триммера волны. Где-то дерн цепляет, где-то недорезает. А к литовочке настолько привыкла рука, что ей плохо сделать ну никак не получится.
К чему весь этот спич? Горбуша — ассемблер с макросами, ибо без макросов серп получится (тоже к слову умею). Литовка — это С. А триммер — все что выше и лучше. Косить гектары даже триммером так себе идея. Тут комбайн нужен. Обкосить канаву литовкой тоже не лучшая идея. Камни, рытвины. Уж лучше триммер. А вот скосить «английский газон» перед домом… Ну ка его, этот триммер. Лучше литовочку. Чтоб результат глаз радовал. Да травку вывезти, а не на месте гнить оставить (привет автоматическим сборщикам мусора). Больше того — в кусту смородины сорняки покосить — так тут и литовки много будет. Тут в сарае серп лежит.
Рачительный хозяин любому инструменту применение найдет. Главное понимать где границы применимости.
Этот комментарий можно сократить до двух слов: "Сперва добейся"
Свое отношение я выразил первым комментарием. Могу повторить. Обсуждать недостатки языка С имеет смысл с теми, кто им пользуется на регулярной основе. Только эти люди знают о нем все. Но ведь они, как правило, и не спорят. Больше того — даже не ввязываются. «Собака лает — караван идет».
Те же, кто «когда-то подходил к этому снаряду», но по тем или иным причинам не стал им пользоваться как раз и превращаются в ярых противников. Можно сказать что в этот раз еще культурно. Обычно такие споры злее. Массивы и указатели. Указатели на функции. Двойные, тройные указатели. Размерность стандартных типов. time_t разного размера. Опять же errno. Имя им легион. В принципе понятно, что язык С давно требует как минимум глубокой модернизации. Но провести эту модернизацию упорно пытаются со времен D и C++. Местами успешно. В свое время в вебе perl легко подвинул С++ — он был банально удобнее.
Сможет ли кто-то из ныне существующих подвинуть C в низкоуровневом программировании? Не знаю. Хабр любит Rust. Мне он не понравился. Я переборол первое впечатление и попробовал его в деле. Нет. Не нравится. Синтаксис. Необходимость переделывания «заголовочных» файлов железок. Итоговый двоичный код. Возможно, это наведенное — следствие плохого первого впечатления. Но для меня показатель еще и в другом. Где работа Rust community? Почему до сих пор на github'е нет синхронизируемого в ванилью репозитария ядра Linux (с переписанными важными частями системы)? Почему нет значимых попыток переписать (U)EFI на Rust? Все ждут пока кто-то за них это сделает? Ну хорошо, пусть ждут. "… Караван идет". А то, что на Хабре очень много решительно настроенных противников С для меня давно не новость. В том же первом комментарии было написано «Это Штирлиц. Сейчас будет драка.» Это было слишком очевидно.
Почему до сих пор на github'е нет синхронизируемого в ванилью репозитария ядра Linux (с переписанными важными частями системы)?
Слишком толсто, попробуйте ещё раз.
Что до мастеров комбика C/C++… Не хочу высказываться на эту тему. С моей колокольни это принципиально разные языки. Их генетический код разошелся очень давно. Потому я просто не знаком с задачами где это надо. Знаю где нужен C++. Знаю где нужен C. Но с трудом могу представить себе задачу, в которой один разработчик должен ответственно использовать оба этих инструмента. И в любом случае не хочу оказаться на месте этого самого разработчика.
Да, конечно — очень часто это игра на грани. Конечно, довольно часто она приводит к очень нехорошим последствиям. Конечно, надо думать как от подобного защититься. Я ж против этого ничего не имею. Беда лишь в том, что любое современное решение это очень плохой компромис. Даже в сравнении со старым и проблемным С.
Впрочем, справедливости ради стоит заметить — сегодня объем кода, производимого компиляторами С едва ли подберется к 1% от кода с других языков. И это соотношение весьма внушительно. Можно сколько угодно кричать о том, что прочность цепи это прочность самого слабого звена. Можно пенять на С говоря смотрите — CVE на CVE сидит и CVE погоняет. Но где хоть какие-то гарантии того, что в оставшихся 99% дырок меньше. Просто нашему 1% уделяется самое пристальное внимание. В первую очередь именно по причине того, что типовые заморочки очень хорошо известны и довольно легко обнаруживаемы.
Согласен — ситуация не нормальная. Только вот обвинить язык С в том, что именно на нем лежит вся вина… Что он провоцирует написание кривого кода… Что он генетически неправильный… Да ну, нафиг. По мне это перекладывание ответственности с программиста на язык… Не правильно это как-то. Впрочем, оценка комментариев как раз говорит о том, что мнение это на хабре не популярно. И я теряюсь в догадках, популярно ли ему обратное. Что любая кухарка должна уметь
У меня нет никаких проблем контролировать переполнение
Интересно, как вы это делали, если переполнение знаковых целых в C — неопределённое поведение.
А возможность разыменовывания любого указателя (а равно арифметика указателей) позволяет весьма эффективно управлять аппаратурой.
Ага, например, писать в порт для чтения и читать из порта для записи.
Да, конечно — очень часто это игра на грани. Конечно, довольно часто она приводит к очень нехорошим последствиям. Конечно, надо думать как от подобного защититься. Я ж против этого ничего не имею. Беда лишь в том, что любое современное решение это очень плохой компромис. Даже в сравнении со старым и проблемным С.
[citation needed]
Можно пенять на С говоря смотрите — CVE на CVE сидит и CVE погоняет. Но где хоть какие-то гарантии того, что в оставшихся 99% дырок меньше. Просто нашему 1% уделяется самое пристальное внимание.
Ну так-то не 1 процент, а где-то 70.
Только вот обвинить язык С в том, что именно на нем лежит вся вина… Что он провоцирует написание кривого кода…
Именно что провоцирует. Всякие телодвижения со стороны программиста, способствующие написанию лучшего кода, дополнительные по сравнению с хреновым умолчанием. В частности, C провоцирует:
- НЕ проверять указатели на NULL
- НЕ проверять границы при индексировании массивов
- НЕ проверять результаты возврата функций, которые могут завершиться ошибкой
- НЕ писать break после ветвей switch
- НЕ оборачивать тело циклов и условных выражений в фигурные скобки
- НЕ вызывать функции освобождения ресурсов на более неиспользуемых значениях
- и ещё довольно много чего, уверен, вы, как более опытный человек, сможете дополнить список.
Нет уж. Мне больше по душе демократия С.
А это не демократия, это анархия. Если опыт IT-индустрии что и показывает, так это то, что писать код на C без уязвимостей — за пределами способностей простого смертного.
[citation needed]
[ignored] Считаем авторскими мыслями. Раз цитата не приведена.
Про 70%… Ну читайте внимательнее. По сути это говорит о последствиях взрывного роста популярности C++. Авторы той статьи сильно больше спровоцировали приход «кодеров» в свои продукты «выкатив» такие надстройки над WinAPI как MFC. Так ведь еще раз — на свете ничего не дается бесплатно.
Да и список ваш. Тот, который на НЕ начинается. Целиком и полностью выдает ровно то, о чем я говорю с 0xd34df00d Все перечисленные проблемы сильно мешают в плюсах. В обычном С память по нулевому адресу это просто память по нулевому адресу. Ее можно читать, ее можно писать. Никто не может ограничивать конституционную свободу автора читать и писать из любого места (а равно делать что хочешь, не противоречащее закону). А все, что противоречит тут же прибивается с помощью SIGBUS/SIGILL, DATA_ABORT_HANDLER, PREFETCH_ERROR_HANDLER и множества других механизмов специфичных для разных платформ. Меня как раз радует возможность писать что-то типа
switch (fn(a,b,c)) {
case x:
case y:
do_required_prepare();
case z:
do_required_job();
break;
case_t:
do_nothing();
break;
default:
err("WTF!\n");
}
И строго по мне, все остальное либо «коммунизм в отдельно взятой песочнице» интерпретируемых языков, либо «олигархический капитализм». Для меня компилятор — партнер и советчик. А не надзиратель в тюрьме. И именно за это любят язык С.
Впрочем, воображение уже рисует цветастую картину. Ночью, под завешенными шторами, на отключенном от интернета компьютере ковыряем залоченный загрузчик myPhone 200 и запускаем на нем код, написанный на находящемся вне закона языке С. Впрочем, завязываю шутить. Есть у моих шуток дурацкое свойство — через некоторое время оказываться пророчествами.
вы ж сами пишете, что на раст вам перекатываться лень (синтаксис там непривычный, заголовочные файлы конвертировать надо…)
Я сказал первое впечатление отрицательное. Я же сказал, что не смотря на это пробовал в деле. И таки конфертировал. И поплевался, но по минимуму освоил синтаксис. И даже результирующий ассемблерный код посмотрел. Спасибо вынужденному безделью во время пандемии. Т.е. результат «не лень» это переписал все свои проекты на Rust? Тогда согласен — лень. В остальных случаях не надо приписывать мне того, что я не говорил.
Более того, сноска в 6.5.3.2/4 прямо говорит, что вы неправы:
Хороший вопрос. У меня есть чипы, на которых ROM размещается с нуля. И вектор сброса там. И как его тогда читать непонятно. И не менее непонятно, чем мне могут помочь в этом плане другие языки (ассемблер — вас это не касается). Потому, неверное, плакать. И страдать. Или, что более вероятно, плюну на эту сноску как это сделали разработчики компиляторов. Но в целом вопрос на пятерку.
Стандарт ограничивает. Более того, стандарт запрещает даже вещи типа...
Да. Но еще раз — компилятор друг. Поэтому ругнется Warning'ом (а может даже и Error'ом). Но никак не запретит мне использовать явное приведение типов. «Ну, раз ты уверен — я не возражаю». А я лишний раз проверю не перемудрил ли я с такими конструкциями и нельзя ли сделать проще и понятнее.
Вообще я смотрю на те примеры, которые приводе Вы и диву даюсь. "Доктор, откуда у Вас такие картинки"?
И правильно что стандарт ЯВНО ограничивает применение подобных конструкций, требуя их четкого подтверждения автором. Разве это говорит против С? По мне как раз «за».
А вас не смущает необходимость следовать всяким там MISRA C при написании кода на сях для автомобилей, например?
Знаете, как все связанное с С — больная тема. Я безусловно признаю полезность MISRA. Вот просто безусловно. Больше того, когда судьбинушка заносит в IAR обязательно ставлю эту галку как минимум на «посмотреть на грабли». Но… Уж очень разные чипы. Уж очень по разному устроена кодогенерация у разных компиляторов (даже не смотря на простоту внутреннего мира С). Потому временами рекомендации MISRA сильно ухудшают читаемости (а значит сопровождаемость) и скорость кода. Потому если нет жестких требований, то «поверю, посмотрю на вывод, где сам считаю нужным поправлю». К счастью (или несчастью) у меня пока не было ни одного проекта где MISRA была бы в обязательных требованиях.
Но ведь это та самая демократия. Хочешь ограничивать свободы — плати соразмерную цену. Нет?
Но потом я пришёл на работу, где люди моим кодом будут торговать на бирже, и где есть реальная ответственность, от материальной на много-много денег до уголовной...
Вы вот упомянули автомобильные системы. Да, там MISRA. Но и там жизнь и здоровье. При чем еще неизвестно где больше. Впрочем, мне вот интересно, а BIOS в тех вычислительных системах, на которых крутой и верифицированный код работает на чем написан?
Опять же речь о применимости инструментов. Об ограничении одних сверху, других снизу. Я совсем не хочу «С везде».
Это редуцированные примеры того, с чем я сталкивался и что приводило к проблемам в продакшене. Могу ещё мноооооого таких примеров привести.
Тяжела жизнь прикладника. Мне бы такое даже в страшном сне не могло присниться. Интересно код в продукт каким путем шел. Не, я понимаю чего хотели добиться в каждом конкретном примере, но хоть убейте не понимаю зачем чесать левое ухо правой рукой, да еще и обязательно пропущенной под левым коленом. Очевидно так смогут не все.
Что до так пугающих множественных UB — так их количество растет вместе с ростом вычислительной техники. Сначала endian-, потом align-, потом многоядерность-многопоточность. Везде, где нельзя гарантировать одинаковый результат на разных платформаю рисуется UB. И это меньшее зло, чем отдавать предпочтение одной платформе и «давить» другую.
Чуть хуже дело обстоит с оптимизацией. Впрочем, я уже говорил в других темах. Основная борьба — это борьба с оптимизатором. Вот тут да… Но, блин — ведь я за это должен быть благодарен как раз прикладникам. Это их стараниями появились странные оптимизации и принудительным inline-ингом или наоборот выносом кода в отдельные функции. Потому привычка писать с "-O none" и в крайнем случае использовать "-O size" давно и неискоренимо выработана. Борьба за размер или скорость — это моя борьба. Я и ее не хочу доверять компилятору.
Ничего вам не поможет, счастливой отладки!
Спасибо. Именно за уничтожение этого кактуса методом сгрызания мне деньги и платят. Больше того — у меня в ряде случаев нет даже отладчика или debug-консоли. И тем не менее, я продолжаю считать С лучшим НИЗКОУРОВНЕВЫМ языком.
Много релевантных ворнингов от компилятора видите?
По разному. Сильно зависит от компилятора. Но тут привычка проверять код на разных компиляторах в параноидальном режиме рулит. Не скажу что они уж очень редки.
а вот кардиостимулятор я бы предпочёл ...
Ваше право. Я, к слову, не знаю про требования к ПО медицинского оборудования (и даже не уверен что они вообще есть). Но сталкивался с требованиями к железкам. Применительно к заданной теме самое тяжелое там обеспечить не «мусор на входе — мусор на выходе», а «мусор на входе — аварийный режим (фиксированная индивидуальная программа)».
На сях… и это не моя головная боль.
Ну так я снова и снова предлагаю вернуться к началу. Может не надо мешать нам грызть кактус. Тем более, что рецептура текилы нам давно известна. Мы рады, что нам сочувствуют. Но менять особо ничего не хотим.
В принципе это и остальных языков касается. Если не сейчас, то через некоторое время. И логично, что изменения в коде изменяют поведение оптимизатора. Ведь компилятор в своих выводах абсолютно прав.
А вот что с этим делать? А ничего не делать. Жить как живется. И не писать «мертвый» код по возможности.
— И это меньшее зло, чем отдавать предпочтение одной платформе и «давить» другую.
— Конечно. Но проблема не в этом, а в том, что no diagnostic required.
Ну так я нигде и не говорил, что С это золотой червонец, который обязан нравится всем. Вы приводили ссылку на стандарт. Мне страшно представить насколько обесценятся предупреждения компилятора, если на каждый чих оттуда выдавать Warn'инг. Кому это реально важно — есть статические анализаторы. Более того, «no diagnostic required» у «хороших» компиляторов не превращается в «diagnostic no required» (странная русско-английская игра слов, призванная сказать что часть компиляторов диагностику таки выдает).
Я бы посмотрел на хотя бы один компилятор, который здесь скажет что-нибудь полезное.
В частности IAR очень любит поругаться на выравнивания. Местами даже не по делу. Нет у меня под рукой единственного проекта где я его Warning не смог побороть, потому привести его не могу. Уж поверьте на слово — ругается. GCC сильно не любит смесь знаково-беззнаковых операндов, способных привести к потере знака в результате. Опять без примеров. Просто потому, что под рукой нет. Но сталкивался. Clang фанатично выверяет форматную строку. Это из самых известных. Вообще, хорошая тема для отдельной статьи. Я, пожалуй, попробую выкроить на нее время. Оно того точно стоить будет.
Но пока у меня выход ядра 5.10(.1) каким-то боком поломал загрузку на I.MX6. Как минимум наблюдаются проблемы с видео и сетью. Видимо удаление платформенного кода не прошло даром. Надо разбираться… Пока не гонят, но когда гнать начнут у меня уже решение должно быть.
… я очень часто встречал людей, которые отключают оптимизации, потому что этот паршивец-оптимизатор глючный, бажный и ломает их хакерский код.
Нет же. Я уважаю коллег по цеху и далек от мысли о том, что оптимизатор «глючный и бажный». Да и вопрос что в Вашем понимании «хакерский код». Мне кажется, хакерский код — это лаконичный, понятный, самодокументирующийся код. Посмотрите на код ядра Linux. В подавляющем большинстве случаев он предельно прост, понятен и не оставляет особого простора оптимизатору. Потому его выключение мало на что влияет. Можно и включить — только это приведет лишь к увеличению времени компиляции. Больше того — временами я делаю тестовые сборки со всеми возможными уровнями. Ровно затем, чтоб убедиться — не ломается.
[OFFTOPIC] В одной из тем я наловил минусов, пытаясь объяснить за что ж я не люблю ST Microelectronics. Так вот как раз за это. CamelCode, излишняя многословность. А когда начинал знакомство с ними еще и зависимость от уровня оптимизации. С моей колокольни фу-фу-фу. [/OFFTOPIC]
Ну и тут есть ещё такой аспект, что… ну, короче, дети же смотрят!
Да. Только вот у нас очень разный подход к этому факту. Я пытаюсь сказать — учите. Начать очень просто, а дальше сами поймете. А вы отпугиваете излишними сложностями. Впрочем, это даже хорошо. Запретный плод всегда сладок. И манит он как раз самых любопытных и любознательных. Потому альфа и омега, лед и пламень, ангелы и демоны… Но именно в паре. Нельзя чтоб одна сторона перевешивала. Надеюсь у меня получилось.
А вообще странное разделение, я его перестал понимать.
Да. Водораздел здесь не очевидный. И каждый его ставит себе сам (если ставит, конечно). Для меня, все что непосредственно взаимодействует с железом — то системное. Остальное — прикладное со своим делением. Но это, конечно, условность. Потому как разработка компиляторов, обработчики протоколов в ядре, стеки типа mac802.11 — безусловно системное программирование, а непосредственно железа вроде не касается.
Впрочем, я стараюсь не отнимать хлеб у прикладников (по своей классификации). И, боже упаси, учить их правильному подходу к программированию. Соответственно ровно такого же отношения ожидаю к себе.
Ну так я нигде и не говорил, что С это золотой червонец, который обязан нравится всем. Вы приводили ссылку на стандарт. Мне страшно представить насколько обесценятся предупреждения компилятора, если на каждый чих оттуда выдавать Warn'инг. Кому это реально важно — есть статические анализаторы.
На самом деле это важно всем. И нет, ни компиляторы, ни статические анализаторы толком не помогают.
int foo(int *ptr)
{
int val = *ptr;
return ptr ? 1 : 0;
}
Чистая единица. val — локальна, и нигде за пределами функции не живет, но раз в нее есть запись из указателя, который не проверяется, значит указатель не NULL — а значит ну его к лешему — return 1 и нафиг. А если убрать присвоение (не вошедшее в бинарь, но участвующее в кодогенерации) проверка вернется. Потому как тогда указателю веры нет.
Можно я второй пример разбирать не буду? Там поведение компилятора ровно так же очевидно. Вся фигня с этими примерами — время жизни локальный переменных. Правда отягощенное высосанным из пальца странным доступом к рядом расположенной переменной. Потому со всей ответственностью — притянуто за уши.
Вопрос подачи материала. Эмоционально
Вообще, кинули бы личкой подобного. Хорошие вопросы для собеседования кандидатов и обучения молодежи. На знание и понимание особенностей работы компиляторов в языка С. Я, в силу склада характера, подобного даже придумать не смогу.
А это, кстати, интересная тема…
Да проще все… Вы сильно увлеченный человек. Ваше право. Я, лет до 25 таким же был. Потом дошло — жизнь программированием не начинается и не заканчивается. Есть и другие темы. Важные и интересные. Да и объять необъятное не получится. Закон качалки гласит — всегда найдется человек, который твоим весом только разминается. Потому плюнул и стал сильно спокойнее относится к тому, что на свете много людей куда более умных, нежели моя наглая морда.
Одна беда — в религиозные споры типа этого не влезать так и не обучился.
А статью жду. И, думаю, все же стоит закругляться. Тут, пожалуй, все уже сказано.
Ага, например, писать в порт для чтения и читать из порта для записи.Емнип, битбэнг на avr как раз так и работает.
Вот хороший пример кода на С, обмазанного достаточным количеством кода на AstraVer для того, чтобы доказать его корректность. Написание всего этого кода (весь проект — гарантированно безопасный загрузчик PE-образов для UEFI) заняло у двух не самых глупых товарищей полгода, а я такой же загрузчик на том же С (но уже без каких-либо гарантий, кроме «от фаззинга не падает» и «мамой клянусь») написал в 2016 году за три дня. В итоге программировать на С так, чтобы гарантировать отсутсвие ошибок, могут себе позволить только те, кто сидит на финансировании из бюджета, и потому по времени практически не ограничен, а коммерческие компании вынуждены бежать, сломя голову, только чтобы на своем месте оставаться, и потому практически весь их код на С не выдерживает никакой критики с точки зрения безопасности.
В итоге недостатки слишком много позволяющего языка пытаются чинить в железе, уже занесли туда теневой стек (Intel CET), подписывание указателей (ARM PAC), тегирование памяти (ARM MTE), и теперь работают над заносом туда же контрактов, которые будет расставлять компилятор, потому что программиста это делать невозможно заставить (CHERI).
Понятно, что для микроконтроллеров, к которых вся прошивка — это конечный автомат на десяток состояний, это все не нужно, и там можно продолжать писать на С спокойно, потому что вся программа влезает в голову одного инженера. Проблемы начинаются там, где в программе уже больше миллиона строк кода, и над ней работает сотня-другая людей непрерывно. Именно там становятся нужны любые возможные способы обеспечить локальность эффектов, предотвратить ошибку до того, как она попала в репозиторий, остановить разработчика от необдуманных поступков вроде создания гонки по данным и передачи данных в соседний поток без использования примитивов синхронизации, т.е. в конце концов именно там мы приходим к необходимости языков вроде Rust.
Короче, если у вас пока что на С все работает и жрать не просит — смело продолжайте на нем писать. А у нас вот давно уже от С геморрой сплошной, а заменить его толком не на что, потому что C++ — это такое же хтоническое чудовище, вид сбоку, а внедрение Rust пока буксует по экономическим причинам (дорого переучивать всю ораву, дорого писать клей, дорого переписывать то, что не получилось приклеить, а дело делать надо уже сейчас).
Драка
А давайте все же скажем, что проблема здесь не в языке C как таковом. Синтаксис языка С сильно проще и понятнее синтаксиса любого ассемблера. При этом в подавляющем большинстве случаев современные компиляторы весьма эффективно перенесут код на С любую платформу и с радостью воспользуются killer-фичей этой платформы при генерации кода. И даже многопоточная и многопроцессорная обработка не противопоказаны языку С.
Проблема современного С, как то не странно — это его стандартная библиотека. Вот она явно требует пересмотра. Все эти errno при фиксированном возврате -1. Даже в ядре возвращается -ERRNO, что сильно более разумно. Все эти странные флаги и параметры времен расцвета железных терминалов и перфокарт. Впрочем, если заменить ее умрет язык. Убьем священную корову обратной совместимости. Этого не простят. Потому, увы, но… Кактус этот еще грызть и грызть… Боюсь, тут даже Rust не поможет. Впрочем, применительно к UNIX, я готов согласиться — init и выше уже не тема для языка С. А вот ядро и ниже — еще какая тема.
А уж для контроллеров — так вообще безальтернативно. Сегодняшний Rust для них — это тот же С, только с непривычным синтаксисом. Да и опять контроллеры — это минимальное время, а минимальное время никак не вяжется с безопасностью. Триада скорость, понятность, безопасность. Как всегда — максимум два из трех. Впрочем, по мне именно С разумный компромис для всех трех. Опять же — может просто потому что для меня это привычный инструмент.
А про большие проекты, с программированием на скорость. Ну да, тут сложно. С одной стороны не поспоришь. Все так. С другой стороны — а разве можно сравнивать анархию с С и порядок и тестирование на других языках. Чертов «человеческий фактор» всегда самый главный. И уж следом идут средства разработки. Впрочем я повторюсь про «init и выше». Время, когда всю систему необходимо было писать на низкоуровневых языках типа С давно прошло. И, если честно, нет о нем особых сожалений.
Хорошо сделанная система, которая взаимодействует с людьми, должна учитывать ограничения этих самых людей, и минимизировать как количество ошибок, как и глубину распространения эффектов от них, а в С вместо этого половина конструкций языка — это undefined behavior, а из другой половины разного рода острые грани торчат, про которые никто толком не знает, пока эти грани в очередной раз не разорвут всю безопасность на немецкий крест. Хороший язык должен по умолчанию следить за тем, чтобы пользователь не творил ерунды, а если ему надо ее творить, чтобы это творение было явным, и чтобы у каждого такого места «пошел в пень, компилятор, я лучше знаю» обязательно стояла табличка «ОСТОРОЖНО, РАБОТАЮТ ЛЮДИ!». А в С эту табличку надо программисту на лбу рисовать перманетным маркером.
Слушайте, я не могу ничего возражать. Безусловно, во всех современных бедах виноваты люди. Это они изобрели атомное оружие, это они устроили глобальное потепление и озоновую дыры. Может чего тут мелочитьсся — всего-то запрещать писать на С (а паче на ассемблере — там косячат даже самы опытные). Я не верю в возможность написания программ без ошибок вообще. Во всяком случае живыми людьми. Не стоит недооценивать изобретательность отдельных индивидов.
Другое дело, что на сегодня я не вижу достойных альтернатив. Как в самолете — тошнит, а выйти не получится. Впрочем, меня уже не тошнит. Тошнило от необходимости писать на ассемблере. Вот тут да. Пришедший ему на смену C казался раем земным.
Больше того — жизнь меня усиленно учит тому, что я сильно недооцениваю производительность современной вычислительной техники. Но с этим уже ничего не сделать. Я честно пытаюсь себя перебороть, но привычка «ксорить указатели» сидит глубоко в подкорке. Как и привычка считать такты и смотреть результирующий машинный код.
Мне, если честно, страшно не хочется жить в мире в котором ошибки программиста исправляет компилятор. Извечная проблема: кто контролирует контролеров? Мне спокойней считать, что самый низкий уровень кода проходит качественное тестирование, а ошибки… Они случаются.
Мне, если честно, страшно не хочется жить в мире в котором ошибки программиста исправляет компилятор. Извечная проблема: кто контролирует контролеров? Мне спокойней считать, что самый низкий уровень кода проходит качественное тестирование, а ошибки… Они случаются.
Компилятор, который испрааляет код, это как раз таки случай C/C++, где вместо того, чтобы не дать вам скомпилировать UB, компилятор соберет то, что ему будет удобнее, иногда даже не предупредив вас об этом
Тогда может сразу из спеки бинарь генерить? :)
Хм. Может я чего-то не понимаю, но если мы умеем доказывать соответствие спеке за конечное время (не для любой программы, а для построенной определенным образом, назовем ее программой на языке Х), то сделать программу соответствующую спеке можем тривиально — просто перебирать возможные программы пока для одной из них не докажем соответствие. Весь процесс займет конечное время. Таким образом если генерация программы из спеки неразрешима, то либо и доказательство соответствия спеке на языке Х неразрешимо, либо язык Х позволяет написать программу не для любой спеки.
Кроме того, в этом случае генерация бинарника по спеке — вполне алгоритмически разрешимая задача.
потому что C++ — это такое же хтоническое чудовище, вид сбокутем не менее не допускать ошибки в плюсах намного легче. Если не писать на «си с классами» конечно же
Я в общем-то согласен с тезисом про границы применимости и инструменты для системщиков. Жил бы С только как кроссплатформенный ассемблер — не было бы проблем.
Однако для меня как прикладиника основную головную боль представляет именно просачивание С туда, где не совсем хочется его видеть. И начинается всё тут с C interface для большого количества чисто прикладных библиотек. И вообще использования С как lingua franca.
К примеру, заголовочные файлы. Почти всегда с макро-константами. Иногда с "особо альтернативными" макро-константами или вообще кусками кода, засунутыми в макросы. Вроде первичной инициализации структур. Если нужно сделать из этого богатства биндинги для чего-то, не являющегося С или С++, приходится либо искать генератор, умеющий такое парсить, или писать руками. Особенно весело для больших библиотек с заголовочными файлами на несколько тысяч строк.
Связанная проблема — макро-константы для условной компиляции. Опять же, решение или надо тщательно искать (если вообще есть), или писать руками.
Ещё одна связанная проблема — зоопарк целочисленных типов. Fixed-width integers появились только в C99.
Короче говоря, я хотел бы видеть в качестве языка описания бинарных интерфейсов что-то более строго типизированное и без макросов.
Короче говоря, я хотел бы видеть в качестве языка описания бинарных интерфейсов что-то более строго типизированное и без макросов.
WASM?
«Dynamic languages may not catch problems at compilation time but if they have a strong type system»
Звучит как-то странно, учитывая что динамическая типизация и строгость/слабость системы типов ортогональные характеристики.
Думал, ошибка перевода, но и в оригинале такая же фигня.
Был же более-менее хороший разбор habr.com/ru/post/161205
Имхо, с С классическая проблема «бросить жалко». Так много времени и денег в его экосистему вложено, что ёжики будут плакать, колоться, но продолжать жрать кактус.
Система сборки — отдельный ужас. Ох как «весело» шерстить на предмет ошибок makefile размером в 250Кб, где к тому же значительная часть кода по 15 раз повторяется. Дублирование кода — это настолько явный антипаттерн, что смело позволяет считать make дерьмом. Именно поэтому поверх него практически во всех мало-мальски крупных проектах набрасывают дополнительные скрипты. В итоге чтобы уверенно собирать чужие проекты на C, вам мало знать синтаксис make-файлов. Вам ещё потребуются знания bash, Perl и Python на уровне, достаточном, чтобы разобраться в проблемах, когда сборка упадёт.
Вы как-то узко понимаете термин «экосистема». На и под С написаны, наверное, миллионы библиотек для тысяч устройств, и, наверное, все типы возможных задач — и это всё тоже экосистема.
Я бы, например, был бы рад иметь бесплатный вариант github.com/coin-or/Ipopt на обычно используемом мной .net, да ещё чтобы с хорошим кодом, но это так не работает.
Если я правильно помню слова коллеги, у нас до сих пор используется версия, где .net обёртка над ipopt, внутри которой c, с которым сконнекчены куски фортрана, потому что изначально ipopt наполовину на фортране написан.
Потому от makefile и уходят, где могут, благо CMake (в разы лучше, хоть и не без своих затей) есть, и учить только его и придётся. Не вижу смысла использовать make в новых проектах совсем.
Ещё есть QMake и Meson, но с теми мне сталкиваться не приходилось особо.
«Dynamic languages may not catch problems at compilation time but if they have a strong type system»Зависит от терминологии. В определениях приведённой статьи — да, в определениях из, например, TAPL(книга), скорее нет, т.к. типы там определяются как статически гарантируемые свойства программы, а динамическая типизация — оксюморон.
Звучит как-то странно, учитывая что динамическая типизация и строгость/слабость системы типов ортогональные характеристики.
Думал, ошибка перевода, но и в оригинале такая же фигня.
Был же более-менее хороший разбор habr.com/ru/post/161205
Косвенно и ± километр из TIOBE можно прикинуть сколько людей пытается изучать тот или иной язык(программистами они вообще никогда могут не стать, но на статистику повляют) и насколько язык удобен в использовании.
Гуглил недавно как в Java добить строку нулями слева до фикс длинны. Я искал что то вроде String.leftPad, но не нашел сам. Через гугл я конечно выяснил что это делается через String.format. Но я увидел и большое количество людей которые делают это руками сами в разных вариациях, вплоть до цикла со сложением строк через "+". Очевидно что вот в этом месте проблема. И я поднял рейтинг языку, просто на пустом месте. Вы скажете — «Ты субьективен! Проблема только у тебя и вообще ты никто.». А вот нифига, во всех библиотеках она примерно так и называется как я и ожидал. Значит люди ждут именно это, а не String.format который пришлось гуглить.
— Разыменование невалидных указателей
— Отвратительная реализация строк с возможностью выхода за их границы
Читая новости об очередных найденных «уязвимостях» в системных библиотеках, создаётся впечатление что из них 99% вызвано исключительно этими недостатками языка. И пора уже признать что ввиду системности этого явления это не вина «плохих» программистов, это именно ущербность самого языка.
Любой язык, который сможет решить две этих проблемы без потери преимуществ C потенциально является его «убийцей».
Работа со строками, а равно форматная строка printf/scanf — это любимая мозоль любого, активно пишущего на языке C.
Языки типа С++ пытаются побороть строки и абстракции драйверного слоя (что сильно важнее). У Apple даже получилось переписать BSD'шное ядро на плюсах. Microsoft уже довольно давно использует плюсовый код в ядерной части своей ОС. Может быть в этом и есть что-то. Но массового перехода нет. Или «мир еще не дозрел», или… Преимущества ощутимы при «корпоративной» разработке, но плохо работаю с открытыми проектами? Не знаю. Для меня пока факт — используется, но не очень активно.
И да, сам язык не имеет ничего против разыменовывания ЛЮБЫХ указателей. Вообще. Он абсолютно бесприкословно выполнит то, то его попросят.
Беда в том, что системно решить и эту проблему невозможно. Нет ни одного чипа, ассемблер которого был бы ориентирован на работу со строками. И нет его по вполне понятным системщикам причинам. Сложно. Дорого. Сильно специфично. Точно так же нет ни одного чипа, ассемблер которого контролировал бы валидность указателей (хотя бы в момент разыменовывания). Опять же — причина ровно та же. Слишком много лишних транзисторов, лишних связей и сложной топологии, лишнего энергопотребления, потраченных на проверку тактов. С, будучи кроссплатформенным ассемблером, наследует все эти болячки.
Языки типа Rust борются с ними выстраивая эшелонированную оборону над ресурсами. Т.е. пытаются сделать то, на что разработчики чипов пожалели транзисторов и тактов. Их право. В определенных случаяю, возможно, и стоит сильно пожертвовать скоростью ради безопасности. Но победа Rust над C на низком уровне как раз и будет грозить резким падением производительности на прикладном. Стоит ли оно того? Ну время покажет. Rust активно растет. Правда пока все больше на прикладном уровне, пытаясь конкурировать не столько с С, сколько с С++. Потому ждем.
Так что «недостатки языка» — это кому как. Если скальпель для хирурга очень острый, то возможно не стоит начинать оперировать. Возможно для всех будет лучше, если такой хирург возьмет не такой острый топор и пойдет дрова рубить. А «уязвимости»… Ну, кто сам без греха пусть первым бросит камень. В конце-концов в мире WEB-программирования (где языка С нет чуть больше чем совсем) они весьма и весьма не редки.
Дык это — такты конечны. Аппаратных блоков контроля указателей и работы со строками нет. Значит контроль программный. Значит такты. При каждом (ужас) обращении к строке или указателю (массиву). Перед одной-двумя ассемблерными инструкциями для изменения байта в массиве, десяток-другой инструкций допустимости подобной операции. А что есть аргументированные возражения? Я бы послушал…
array sample[200] of int;
int i;
fn do_some_with_array()
{
i = get_number_from_user();
a[i] = i;
}
Чтоб так, как описываете вы. Я могу понять, если будут требоваться уточняющие параметры для описания i (индекса). Но где гарантия что их не забудут или они будут правильные? А если массив не статический, а выделяемый из HEAP в процессе работы? Как это можно учесть в момент компиляции?
Если найдется ссылочка «на почитать» буду благодарен. Потому как для меня это пока непонятно.
Да и вариант с массивом очень прост и по сути (ожидаемо) уперся в валидацию ввода пользователя. А посложнее? А если не ввод? А если вычисление или получение из регистра? Мне ниже ссылку дали. Пожалуй остальное после прочтения. Ладно, будем ждать. Вдруг действительно у «ржавых» все получится. Мешать им я точно не намерен.
Почитайте «Type-Driven Development with Idris»
Спасибо. Почитаю.
Пока мне кажется, что вариант запутаться в обозначении границ (или поломать все, изменив это описание в одной из библиотечных функций) будет даже проще, чем выстрелить себе в ногу с указателями. Впрочем, я все же сначала почитаю.
Провалидировать пользовательский ввод — это вполне себе стандартная рекомендация для любого языка. И на том же C она ровно так же прекрасно сработает. Другое дело, что С не будет требовать. И даже просить. Но это и один из самых простых примеров. Правда, чего уж там, один из самых распространенных вариантов накосячить.
Видите ли, в ситуации когда мы делаем get_number_from_user, мы обязаны добавить проверку. Хоть вручную, хоть автоматически… Потому что данным от пользователя доверять нельзя, никогда. И такты на проверку придётся потратить, от языка это не зависит.
Однако, немного изменим условие задачи:
i = get_number_from_user();
a[i] = i;
a[i+1] = i+1;
Здесь нормальный компилятор уже не будет проверять что i+1>0, так что будет сделано всего 3 сравнения, а не 4 как можно было бы подумать.
Теперь добавим ручную проверку:
i = get_number_from_user();
if (i<0 || i>=199) throw wtf;
a[i] = i;
a[i+1] = i+1;
Нормальный компилятор должен сообразить, что никаких автоматических проверок в этот код добавлять уже не нужно. Это должно работать даже без завтипов, пусть с ними и выходит красивее.
Первый пример однозначно не безопасен. Для того, чтобы оставить его в «production» коде нужны серьезные причины. Например строго известный размер массива a и строго известные ограничения возвращаемого get_number_from_user() значения. По сути именно это и даст Rust (и иже с ним). Больше того, при попытке что-то поменять внутри get_number_from_user() или размер a поднимется паника — ломаем соседний код. Второй вариант — извечная классика С. Я, конечно, из ссображений педантичности все же сделал бы так
do {
i = get_number_from_user();
} while ((i<0) || (i>=199));
a[i] = [i];
a[i+1] = i+1;
Но это косметические детали.
Кажется, вы описываете завтипы, которых нет в Rust. А Rust умеет выкидывать проверки при обращении к элементами массива?
Проверки времени жизни существуют только на этапе компиляции. А если вам нужно убрать проверку на выход за границы массива, всегда есть get_unchecked.
Returns a reference to an element or subslice, without doing bounds checking.
Это то самое "я лучше знаю, что делаю", только выраженное явно.
Дальше простынь не читал
Применение в качестве средства программирования языка высокого уровня — упирается в ограничения платформы или структуры и постоянно для конкретных задач требует расширения
Применение низкоуровневых языков на базовых логических конструкциях (а С конечно один из таких) — приводит, при наличии гибкости, к сотням сложных обработок и однотипных повторений. Выведение их во фреймворки БЕЗ централизованной модерации — ничего не решает.
Я думаю что С умрет только тогда, когда появится такой инструмент программирования — который позволит погружаться разработчику до машинных кодов, предоставляя в основе своей язык 4-го или даже 5-го уровня для описания алгоритмов. И конечно он должен иметь развитые семантики и инструменты работы с данными и их метамоделями.
А по поводу накручивания абстракций, я еще 5 лет назад писал статью.
Например, в случае сборщика мусора: если он есть и прибит гвоздями к языку (как в Go или D) — язык уже не может быть «системным». Если его нет вообще — это неудобно для высокоуровневого программирования (как в С++). А вот если он есть, но в виде «расширения», которое можно включить или отключить в свойствах проекта — это совсем другое дело.
ИМХО сборщик мусора — слишком инвазивная вещь.
Если вы не хотите видеть GC в системе типов, вы будете всё равно включать его глобально. Причём такой "глобальный включатель" будет срабатывать при наличии хотя бы одного модуля, требующего GC. С принудительными сканами всего и вся и всё равно проблемами, когда кто-то будет случайно руками удалять управляемый объект.
Если же вы хотите выделить сборку мусора в отдельный тип smart pointer'a, у вас будут проблемы с просачиванием его везде, включая сигнатуры методов, поля структур и т.п. Плюс — корни GC будут у вас отдельным типом. Который надо будет аккуратно раскладывать на стек.
Пока что приемлемый сценарий, который я вижу — локальное отключение GC для некоторых значений или типов.
Fin
На мой взгляд главная проблема в Си, что он перестал развиваться. Комитет по стандартизации занимается откровенной херней. Ну это не удивительно учитывая, что там есть представители Майкрософт, при том, что сама она не осилила даже c99. В c11 ввели какую-то убогую библиотеку нитей. В 2018 вообще ничего нового не ввели.
C++ развивается и пытается отвечать на вызовы времени, на запросы сообщества.
В Си даже расширения которые поддерживаются всеми компиляторами не могут стандартизировать.
Нынешнее программирование с современными языками — полнейший мрак. Программы потребляют гигабайты, а функциональность и качество только снижаются. Гигабайты!
C печально известен возникновением таких проблем, как переполнения буфера. C — это язык, позволяющий выстрелить себе в ногу слишком большим количеством способов.
Для критических применений есть своды правил, например MISRA. Никто не мешает следовать им и продолжать разрабатывать действительно критически ответственные приложения на «опасном» C. Или кто-то уже разрабатывает или рискует разрабатывать что-то подобное на Java? Я вот побоялся бы сесть в автомобиль у которого АБС написан на Java или Python, например, в котором «так тяжело выстрелить себе в ногу».
Мы недавно сравнивали Rust с C/C++ в контексте производительности (обусждения на Hacker News https://news.ycombinator.com/item?id=24960108 и Reddit https://www.reddit.com/r/programming/comments/jjtobp/fast_programming_languages_c_c_rust_and_assembly/).
Rust позволяет писать более безопасный код, хотя C++ движется тоже в эту сторону. Интересный доклад на эту тему с CppCon'20 Closing the Gap between Rust and C++ Using Principles of Static Analysis.
Но Rust по своему дизайну делает разработку быстрого кода сложнее (примеры приводил в блоге).
Go для утилит типа ls — вполне, но для ядра ОС, например, очевидно — нет.
Может, действительно, стоит оставить язык Си в покое? Раз он дожил до стольких лет и все еще популярен, видимо есть там что-то, что не убить никакими «инновациями».
Касаемо прикладного софта — соглашусь.
Раз он дожил до стольких лет и все еще популярен, видимо есть там что-то, что не убить никакими «инновациями».
Есть, легаси. А ещё дикая косность инженеров, занимающихся программированием для встраиваемых систем.
p.s. не кодил на rust.
Вместо минусов предложите язык для ядра, гипервизоров. Нет таких. Есть попытки внедрять С++, но там многие вещи приходится отключать.И в чем проблема? В критичных местах не используем продвинутые фичи.
Rust разве что……Чтобы понять недостатки Rust, надо пописать на Rust.
p.s. не кодил на rust.
ИМХО, для базы/ядер почему бы и нет
Есть попытки внедрять С++, но там многие вещи приходится отключатьисключения — всего лишь один из инструментов с++, пользоваться ими никто не заставляет. У вас позиция такая, словно лишний для конкретного случая инструментарий делает язык менее применимым, по факту это не так. Моё личное мнение — с++ можно выбрать вместо си примерно всегда, т.к. даже базовое подмножество с++ функциональнее инструментария чистого си.
нужен опытный в С++ мастер, который скажет, что подаванам можно пользовать иль нет
исключения — всего лишь один из инструментов с++, пользоваться ими никто не заставляет
За исключением того, что хороший кусок стандартной библиотеки завязан на использование исключений для оповещения об ошибках. ЕМНИП стандарт вообще не предусматривает работу с отключенными исключениями.
Как пример, мы теперь имеем двойные интерфейсы в std::filesystem
, причём некоторые методы, возвращающие статус через std::error_code
(std::filesystem::directory_iterator::increment), всё равно кидаются исключениями.
А ещё кроме исключений у нас есть std::error_code
, пропозалы на std::outcome
, std::expected
и deterministic exceptions Саттера, и дичайший зоопарк методов регистрации, эскалации и обработки ошибок в разных фреймворках (Qt, ау!).
Короче, с С++ будет проблема — на каком именно диалекте вы хотите писать? И не дай бог ваш диалект не совпадёт с диалектом закрытой либы за много чемоданов денег, которую вам кров из носу надо использовать...
За исключением того, что хороший кусок стандартной библиотеки завязан на использование исключений для оповещения об ошибкахв либах, которые не депрекейтят (типа iostream), стараются дублировать API для возврата ошибок через error_code. Разве что ошибки аллокации только через исключения обрабатывать, но там шибко много приколов. В тот же rust ради обработки ошибок аллокаций затащили механизм, повторяющий по принципу работы исключения. И sigkill никто не отменял…
А ещё кроме исключений у нас есть std::error_code, пропозалы на std::outcome, std::expected и deterministic exceptions Саттера, и дичайший зоопарк методов регистрации, эскалации и обработки ошибок в разных фреймворках (Qt, ау!).проблема в том, что исключения — самый универсальный способ обработки ошибок, но его не любят из соображений производительности (хотя иногда они и быстрее выйдут). С сигналами/слотами Qt'а например тяжело писать последовательный код, std::error_code — хорошая штука, ровно до тех пор, пока не надо кинуть ошибку с неконстантным текстом; в других случаях текст+код ошибки приходится возвращать способами, больше похожими на костыли. Кстати забавно, можно было бы сделать error_code так, чтобы он держал полноценную строку, которая с парой твиков отлично бы работала с константными текстами ошибок.
Короче, с С++ будет проблема — на каком именно диалекте вы хотите писать? И не дай бог ваш диалект не совпадёт с диалектом закрытой либы за много чемоданов денег, которую вам кров из носу надо использовать...как раз эта проблема решаема, т.к. с++ поддерживает много видов обработок ошибок. Вот если бы с++ например не умел в исключения, а вам бы приходилось оборачивать либу какого-нибудь языка которая ими кидается, было бы больнее.
Если вы про панику, то механизм её перехвата существует только для того, чтобы не пропускать панику в FFI слой.ну паника под капотом сделана через тот же механизм, что и с++ исключения
Для несведущих — коду с исключениями недоступные сильные оптимизации. Обсуждается в профильных науч.группах
Для несведущих — коду с исключениями недоступные сильные оптимизации. Обсуждается в профильных науч.группах
А поделитесь ссылочкой. Там какая-то фундаментальная проблема с раскруткой стека, отдельным хранилищем для данных или необходимостью RTTI для перехвата?
Страуструп на предложение Саттера по deterministic exceptions ответил в том духе, что не надо городить огород и лучше просто оптимизировать те исключения, что уже есть. Или это ответ в стиле git gud?
Там какая-то фундаментальная проблема с раскруткой стека, отдельным хранилищем для данных или необходимостью RTTI для перехвата?функции, в которых несколько landing pad'ов, сложнее инлайнить и делать перестановки. Также растет объем кода этих функций, что еще дальше усложняет инлайнинг. Просто у Siegmarl слишком сильная формулировка, я бы перефразировал как «некоторые оптимизации недоступны»
Его блог с разъяснениями и сам документ
Оптимизировать ф-цию с несколькими точками входа-выхода, которую вызывает еще ф-ции с несколькими точками вх-вых итп… в общем случае нельзя, в отличие от 1 вход-1-выход.
И так далее и мы упремся в слабую PGO и проблемы с простотой ABI.
С сигналами/слотами Qt'а например тяжело писать последовательный код
Вопрос не в последовательном коде. Вопрос в том, чтобы корректно выловить ошибку, произошедшую в некоем асинхронном вызове, показать её пользователю и продолжить работу дальше. В случае с Qt из слота даже нельзя ничего вернуть. В одном из моих предыдущих проектов исключения вкупе с перегрузкой QCoreApplication::notify
позволяли прописать обработку всех необработанных обломов в одном месте. Сейчас сижу на QML, который ни разу не exception-neutral.
как раз эта проблема решаема, т.к. с++ поддерживает много видов обработок ошибок. Вот если бы с++ например не умел в исключения, а вам бы приходилось оборачивать либу какого-нибудь языка которая ими кидается, было бы больнее.
Как раз в этом и состоит проблема. Каждый городит что-то своё. Я не настаиваю на исключениях. Пусть будет какой-нибудь вариант Result'а. Но блин везде. Унифицированно. А не так, что "здесь играем, здесь не играем, здесь рыбу заворачивали".
Касательно другого языка — с высокой вероятностью вам придётся писать клей, даже если и там, и там исключения. Потому что если даже и там, и там они нативные, никто не даёт гарантию, что они совместимые. Даже если и там, и там под капотом SEH.
Потому что паттерн observer не для этого.
Все мои кутешно-плюсатые юкзейсы с асинхронщиной покрывались QFuture + QFutureInterface + собственными темплейтными обмазками, дающими эту (и самодельному подобию Either) типа-монадические интерфейсы.
Не совсем точно выразился. Имеется ввиду любой вызов слота, происходящий асинхронно. А QML предпочитает именно асинхронные вызовы. QFuture это конечно прекрасно, но Qt/QML не рассчитан на его применение повсеместно. Что приведёт к boilerplate везде. Корректное заворачивание нативной логики, чтобы она не обрушила QML engine, тоже требует никак не проверяемого компилятором бойлерплэйта везде. А всего-то надо было добавить хук, позволяющий обернуть место вызова из скриптового движка в нативный код. плюс нормальный сигнал QQmlEngine::exception
, вызываемый если скриптовое исключение не было обработано. А не кошмарик QQmlEngine::warnings
, перехватывающий вообще всё подряд.
Лично я пишу на С абсолютно все: от микроконтроллеров до бэкенда веб-морд и всяких сервисов. Очень простой язык — тем он и хорош. Нет нужды читать талмуды мануалов, как в случае, скажем, с С++: достаточно осилить книжку K&R.
Эдик, ЛОР в другой вкладке.
Лучше С языков не было, нет и не будет никогда!!!
А всякие ваши хипстерские педеrust'ы и прочие goвна ни для чего серьезного не годятся! И уйдут буквально через несколько лет…
Тот же пытхон уже давным-давно забыли бы, если б не толпы вантузоидов, которым не завезли баша вменяемого!
Забавно, что код должен хорошо читаться, но с названием этого языка в наших краях не повезло, и сложно читать тексты про Си, когда вместо "Си" — "С".
Не хватает ЯП занимающий промежуточное место между С/С++ и ассемблером. Такой ЯП может быть высокоуровневым ассемблером, вроде UASM, только более высокоуровневый.
Просто между изобретением С, и текущим моментом, появилось много разного железа, не ложащегося прямо на С. Но это судьба любого языка.
Даже статья была про это
Или как когда-то давно язык АЛМО.
А я продолжу писать на С, без преувеличения высокопроизводительный код, по сравнению с выше перечисленными инструментами.
И вообще не понятно, автор подобных статей, их что заставляют на Си писать, чем то угрожая?
А я продолжу писать на С, без преувеличения высокопроизводительный код, по сравнению с выше перечисленными инструментами.
А вы действительно сравнивали или это голословное утверждение?
Как я писал я совершенно не против Python`а, но использовать для парсинга к примеру HTML и XML — я его не буду. Но я только «За», если это будут делать другие.
Поэтому я ни не понимаю претензию в данном случае к Си. Вас кто то заставляет его использовать?
Это всего лишь инструменты, каждый Сам выбирает, что ему использовать.
Немного не понял, а зачем Вы, попробуете что нибудь сделать не на С?
Вы что с чем сравнить хотите ?
Мне бы тоже интересно было.
Вы можете запустить свой код в цикле на определенных параметрах строки и подстроки и сказать время отрабоьки цикла, после чего я пришлю скомпилированный exe-шник(да по винду) и вы проверите время моего скрипта?
Так возможно ?
Будет как раз интересно сравнить тупой алгоритм на С, с хитро-закрученным, так что все честно.
Не люблю высылать исходники, не знай почему :(
Строка:?
Подстрока:?
Кол-во итераций цикла:?
Кол-во циклов: 9999999
Подстрока_1:Hello
Подстрока_2:&lloH
Подстрока_3:Hello1
Подстрока_4:HelloHello
У меня core i5 9600.
Компилировал на VS2017, x64, O2:
На первой подстроке у меня такое время(у меня несколько методов, все они по сути прямолинейные, но немного по разному ведут себя при разных параметрах):
-Время в миллисекундах
-Так же в этой время входит подсчет номеров элементов вхождения подстрок.

Из скрина видно, что наименьшее время — это 727 мсек, наибольшее 2006.
Или у нас с Вами слишком разные процессоры или че то не понятно. 4.5 секунды много получается.
Скомпилировал Ваш код на VS2017, x64, O2:
-Проверял поочередно по одной подстроке в цикле:
Такое получилось:
Подстрока--------------Ваш код, мс: ------------Мой код, мс
-----------------------------------------------------(лучш/худ)
Hello-----------------------1483---------------------727/2006
&lloH-----------------------1217--------------------179/1526
Hello1----------------------1524--------------------357/1769
HelloHello------------------1581--------------------279/2402
C 15:05
Это сравнение, мягко выражаясь, некорректное.
Ну не понимают люди, что для решения задачи всегда надо потратить не меньше определенного числа тактов процессора. А тратить их эффективнее всегда находясь как можно ближе к процессору. В этом плане ассемблер — самый эффективный. Но и самый сложный (как в плане написания, так и в части сопровождения). С следующий. Остальные хуже.
Нет, эти адепты верят к то, что контроль целочисленных переполнений обязателен, а знание в произвольный состояния кеша процессора позволит «улучшить» код. И вообще в процессоре есть магические инструкции, доступные только их любимым языкам, которые в разы увеличивают производительность на любых операциях. Будь то ввод-вывод или обработка строк.
Я думаю не стоит их разубеждать. Пускай верят во что хотят.
Из этого следует с наибольшей правдоподобностью только одно предположение: а может быть, просто не стрелять? Ну да, язык и качественный код на нем требует качества кодера. Да, это не совсем согласуется с общераспространенными современными практиками «х***к и в продакшен». Но испытанная временем бест практис такова, что если бордель теряет прибыль, надо не кровати переставлять, а эмплойерш менять.
Согласен, D надо упомянуть. Сделать язык со сборщиком мусора и при этом одновременно без memory safety — это надо уметь.
Но AnthonyMikh тоже неправ. На D можно писать без сборщика мусора, или с '@ nogc' кусками, и с мемори сэфети там все хорошо (единственное исключение — Сишные юнионы).
Еще добавили Растовский (точнее из линейного программирования) механизм заимствования указателей, но никто пока не умеет им пользоваться…
Заменой С является D --BetterC. Исключается 90% Сишных родимых багов, ценой правки 2% кода. Чтобы 2 раза не повторяться — в BetterC нет GC и классов, хотя есть шаблоны и куча всего, так что все же получается >>> C
Нужна ли нам замена языка C?