<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Язык Си</title>
    <description>Все, что нужно знать для изучения Си — одного из старейших языков программирования — и его тонкостей.</description>
    <link>https://tproger.ru/tag/c-language</link>
    <atom:link href="https://tproger.ru/tag/c-language/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Fri, 25 Sep 2026 18:18:25 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Язык Си</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Простой RPC на Си для Linux-приложений</title>
      <link>https://tproger.ru/articles/prostoj-rpc-na-si-dlya-linux-prilozhenij</link>
      <comments>https://tproger.ru/articles/prostoj-rpc-na-si-dlya-linux-prilozhenij?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[dsn76]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/prostoj-rpc-na-si-dlya-linux-prilozhenij</guid>
      <description><![CDATA[<p>Как просто вызвать функцию из другого приложения на Linux.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/prostoj-rpc-na-si-dlya-linux-prilozhenij">Простой RPC на Си для Linux-приложений</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 10 Sep 2026 17:38:38 GMT</pubDate>
      <content:encoded><![CDATA[<p>Терминал один: ./log (можно запустить несколько экземпляров). Терминал два: ./clc (-//-), Терминал три: ./app . В выводе первого появляется LOG("Hello, world, from app! my pid=..."). Вызовы log_write("Hello") и calc_add(1, 2) в app — обычные С-функции, но выполняются они в процессах log и clc . Вся сериализация параметров функций скрыта в X-макросах, вручную это делать не нужно. Для ипользования в своих приложениях: подключить в свои исходники #include "libsrpc.h", описать прототипы экспортируемых функций в ./src/libsrpc_rpc_functions.h (это часть исходников самой библиотеки, а не отдельный публичный API-заголовок), пересобрать libsrpc.so и слинковать её в своё приложение с флагом -Wl,--no-as-needed . Подробнее — в ./example.</p><p>Есть классическая проблема: изолированные процессы — хорошо для надёжности, но хочется иногда позвать функцию из соседа, как будто она лежала в той же библиотеке. Стандартные IPC — это всегда протокол: описал интерфейс, сгенерировал стабы, поднял сервер, прописал адреса. simplerpc предлагает путь короче: ты пишешь обычную функцию на Си, линкуешь библиотеку — и она автоматически становится RPC-методом, доступным другим процессам на той же машине.</p><p>Архитектура держится на трёх решениях. Во-первых, данные едут не через сокет, а по разделяемой памяти — SHMEM. Аргументы вызова лежат в общем сегменте, отображённом по одному виртуальному адресу во всех процессах, и копирования между адресными пространствами нет. Сокет используется только для сигналов: регистрация функций, передача дескриптора памяти (SCM_RIGHTS), обнаружение смерти клиента. Во-вторых, свой аллокатор — транзакционный TLSF с откатом при падении процесса. Межпроцессный мьютекс встроен прямо в структуру пула, а если владелец мьютекса погибает, следующий автоматически откатывает незавершённую транзакцию. Пул консистентен без внешнего сторожа. В-третьих, вместо стандартных примитивов синхронизации — POSIX-семафоры в разделяемой памяти и lock-free MPMC-очередь для передачи задач от клиента к воркерам.</p><p>Но самое интересное — как демон оказывается в системе. Исполняемый файл демона не лежит на диске. Он встроен в libsrpc.so в виде C-массива, записывается в анонимный memfd целиком в оперативной памяти и запускается через fexecve(). При загрузке библиотеки любым приложением автоматически форкается демон. Если процессов несколько — проигравший гонку bind() на абстрактном Unix-сокете молча завершается. Когда последний клиент отключается — демон выходит, а память исчезает вместе с последней ссылкой на memfd. Никакого PID-файла, никакого init-скрипта, никакого сервиса. Библиотека сама себя разворачивает.</p><p>Библиотека организована так: guard daemon (фоновый координатор), транспорт (Unix-сокеты и SCM_RIGHTS), аллокатор TLSF с транзакциями, сборщик мусора в разделяемой памяти с hazard pointers, RPC через X-макросы (один файл — единственный источник истины), динамическая линковка через weak alias, дескрипторы процессов и потоков, lock-free очереди и синхронизация. Всё это — в bench/ можно найти бенчмарки, если захотите сравнить сами.</p><p>Попробовать три команды: mkdir build &amp;&amp; cd build &amp;&amp; cmake .. &amp;&amp; make, затем в одном терминале ./log, в другом ./app. Готово.</p><p>Ограничения: только Linux, только локальные процессы на одной машине, ранняя стадия развития — API стабильностью не отличается. Функции с переменным числом аргументов не поддерживаются, указатели осмыслены только если адресуют разделяемый пул.</p><p>Репозиторий: <a href="https://github.com/dsn76/simplerpc" rel="nofollow">github</a>, лицензия Apache-2.0. Если интересно — смотрите код на Си.</p>]]></content:encoded>
    </item>
    <item>
      <title>Antirez про новый Redis Array: 4 месяца работы и AI как safety net для системного кода</title>
      <link>https://tproger.ru/translations/antirez-pro-novyj-redis-array-4-mesyaca-raboty-i-ai-kak-safety-n</link>
      <comments>https://tproger.ru/translations/antirez-pro-novyj-redis-array-4-mesyaca-raboty-i-ai-kak-safety-n?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/antirez-pro-novyj-redis-array-4-mesyaca-raboty-i-ai-kak-safety-n</guid>
      <description><![CDATA[<p>Salvatore Sanfilippo (antirez) рассказал о 4 месяцах разработки нового типа Array в Redis: спецификация руками, AI-ассистент как safety net, ARGREP с regex.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/antirez-pro-novyj-redis-array-4-mesyaca-raboty-i-ai-kak-safety-n">Antirez про новый Redis Array: 4 месяца работы и AI как safety net для системного кода</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 05 May 2026 13:15:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Salvatore Sanfilippo (antirez) <a href="https://antirez.com/news/164">опубликовал короткий рассказ</a> о четырёх месяцах работы над новым нативным типом данных в Redis — <b>Array</b>. Работу он начал в первых числах января. Его наблюдение, ради которого пост и написан: AI стал рабочей опорой («safety net») для системного программирования. Он позволил Сальваторе не идти на компромисс по архитектуре, прогонять громоздкие задачи без выгорания и дотягиваться до уровня сложности, который один человек обычно пропускает. <a href="https://github.com/redis/redis/pull/15162">PR #15162</a> только что приземлился в репозиторий.</p><p>Перевод и пересказ короткой заметки автора Redis для русскоязычной аудитории — четыре месяца разработки, изменение внутренней архитектуры в середине пути, ARGREP с регулярными выражениями через TRE и общий вывод про связку «человек + AI» в инфраструктурном коде.</p><p><b>Что вышло.</b> В Redis приземлился новый нативный тип Array с поддержкой числового индекса как части семантики (PR #15162). Четыре месяца работы; команды ARSET, ARSCAN, ARPOP, ARGREP, ARINSERT.</p><p><b>Спецификация — первое.</b> Месяц ушёл на ручное написание спецификации: обоснование типа, C-структуры, разрежённое представление, семантика курсора для ring buffer и ARINSERT. Сначала с Opus, потом с GPT 5.3 / Codex.</p><p><b>Архитектура поменялась в середине.</b> Изначально были два уровня директорий и slices двух типов (sparse и dense) — этого не хватило для ARSET с очень большими индексами. Перешёл на «super directory of sliced dense directories» с slice по 4096 элементов. Без AI «срезал бы углы» — с AI пошёл на extra mile.</p><p><b>ARGREP с regex.</b> При тестировании Сальваторе начал хранить файлы Markdown в Array — для своей базы знаний. Так появилась идея ARGREP. Взял библиотеку TRE (за гарантии по времени против патологических паттернов), оптимизировал её для матчинга foo|bar|zap и закрыл несколько проблем безопасности.</p><p><b>Главный вывод.</b> AI — не замена человека в системном программировании, но «safety net» для громоздких задач (32-битная поддержка, тесты алгоритмов) и виртуальная команда ревью. Спецификация по-прежнему пишется человеком, и она же ключ ко всем последующим этапам.</p><h2>Месяц первый: спецификация руками</h2><p>Сальваторе подчёркивает: даже с AI первый месяц был полностью ручной работой над спецификацией. Документ описывает обоснование нового типа, C-структуры, разрежённое представление, точную семантику курсора для ring buffer и команды ARINSERT.</p><p>Дальше пошёл back-and-forth с моделью: сначала с Claude Opus, потом, когда вышел GPT 5.3, переключился на Codex. С тех пор все системные задачи делает только на GPT 5.x. Промежуточные обсуждения с моделью качественно меняли спецификацию: интеллектуальные вызовы про лучший дизайн, что переусложнено, что — недостаточно проработано.</p><h2>Месяцы второй и третий: автокодинг и пересмотр архитектуры</h2><p>Со второго месяца Сальваторе начал реализацию через <i>automatic programming</i> (его термин для написания кода с AI-ассистентом): постоянное ревью того, что пишет модель. И тут наткнулся на проблему — выбранный уровень индирекции оказался неправильным.</p><p>Изначально была схема: два уровня директорий и slices (sparse и dense). Этого не хватало для сценария вида ARSET myarray 293842948324 foo — то есть когда индекс большой, а массив должен оставаться разрежённым без огромных аллокаций.</p><blockquote>Поскольку у меня был AI, я не пошёл на компромисс — решил пройти extra mile.</blockquote><p>Под определёнными условиями структура данных меняет внутреннюю форму, превращаясь в super directory из sliced dense directories, которые в свою очередь указывают на сами array slices (по 4096 элементов на slice по умолчанию).</p><p>Это и дало одновременно «как настоящий массив» с точки зрения внутреннего представления, и нужные характеристики по памяти. ARSCAN и ARPOP теперь сканируют существующие массивы за время, пропорциональное числу элементов, а не длине диапазона.</p><p>Затем — чтение всего кода построчно. Тип покрыт массивным тестированием (опять же с помощью AI), но «работает поверхностно» не значит «оптимально». Сальваторе нашёл много мелких неэффективностей и дизайн-ошибок, которые ему не нравились, и начал процесс ручной и AI-ассистированной перезаписи модулей.</p><h2>Появление ARGREP — от своей задачи к команде</h2><p>Когда стресс-тестирование Array на разных кейсах подтвердило, что структура годится, Сальваторе начал моделировать сценарии использования. И тут, как часто бывает, личная задача подсказала фичу: он начал хранить файлы Markdown прямо в массивах — потому что они хорошо ложатся в этот тип.</p><p>Параллельно работал с агентами на других задачах и понял, что ему нужна централизованная база знаний из файлов Markdown под нужные навыки. Из своей потребности родился ARGREP. Но захотелось не просто поиска по подстроке — захотелось регулярных выражений.</p><p>Выбор библиотеки regex — отдельная история. Сальваторе остановился на <a href="https://laurikari.net/tre/">TRE</a> от Ville Laurikari: когда regex встраивается в Redis, важно гарантировать отсутствие патологических паттернов по времени и памяти. Но у TRE оказалась неэффективность в одном специфичном и очень полезном кейсе — матчинг alternation вида foo|bar|zap.</p><p>С помощью GPT он оптимизировал библиотеку для этого кейса, заодно зафиксил несколько потенциальных проблем безопасности и расширил тесты. После этого ARGREP с честным regex был готов к мержу.</p><h2>Главное наблюдение: AI как safety net</h2><p>Сальваторе формулирует главный вывод так: для high-quality системного программирования по-прежнему нужно быть полностью вовлечённым — но AI расширил «зону комфорта». Без него Сальваторе не пошёл бы на тот уровень сложности, который выбрал для нового типа.</p><p>AI выступил safety net в двух конкретных аспектах:</p><ul><li><b>Громоздкие задачи без выгорания.</b> Например, поддержка 32-битной архитектуры, которую он добавил и протестировал отдельно. Это та работа, что обычно отнимает мотивацию и силы — с AI она прошла без обычного истощения.</li><li><b>Виртуальная команда ревью</b>, которая отлавливает очевидные баги в сложных алгоритмах. Не замена тестам и не замена самому Сальваторе — но дополнительный слой, который ловит «глупости» до того, как они уйдут в код.</li></ul><p>При этом Сальваторе подчёркивает: огромная начальная спецификация — ключ ко всему остальному. Без неё невозможно было ни прогнать ревью каждой строки в sparsearray.c и t_array.c, ни решать, что переписывать, ни понимать, какой именно компромисс ты только что принял.</p><h2>Что взять на заметку разработчику</h2><ol><li><b>Сначала спека, потом AI.</b> Если задача системная — потратьте первый этап на ручное написание спецификации. AI может качественно её прокачать через диалог, но не сгенерировать с нуля.</li><li><b>Не идите на компромисс по архитектуре, если AI это закрывает.</b> Громоздкая правильная реализация теперь под силу одному человеку. Если внутреннее представление кажется «не тем» — пересоберите его, пока спека ещё свежая в голове.</li><li><b>Ревью каждой строки.</b> AI хорош в тестах и поверхностном «работает», но качество кода остаётся за вами. Без построчного чтения после того, как «всё работает», оптимизировать дизайн — на ощупь.</li><li><b>Чередуйте модели.</b> Хотя бы две (например, GPT 5.x и Claude). Это не страховка от падений API, а способ увидеть проблему с разных углов.</li><li><b>Следите за тем, что под рукой.</b> Сальваторе нашёл идею ARGREP не через roadmap, а через собственный сценарий: хранил Markdown в Array, понадобился полнотекстовый поиск.</li></ol><h2>Выводы</h2><p>История Redis Array — короткий, но содержательный кейс того, как меняется планка инфраструктурного программирования с приходом AI-ассистентов. Не «AI пишет код», и даже не «AI делает программиста быстрее в 5 раз». А «AI убирает потолок сложности, который раньше задавался выгоранием и страхом ошибиться в дальнем углу системы».</p><p>Похожий тренд мы недавно <a href="https://tproger.ru/news/github-perepisal-plan-moshhnostej-v-30-ai-agenty-piwut-kod-byst">разбирали со стороны GitHub</a>: их CTO признал, что план по 10-кратному наращиванию мощностей пришлось переписывать в 30-кратный — потому что объём AI-сгенерированного кода вырос быстрее, чем планировали. Со стороны автора одиночного проекта это выглядит так же: новый этаж сложности достижим без новой команды.</p><p>Источник: <a href="https://antirez.com/news/164">Redis array type: short story of a long development — antirez.com</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>ИИ-агенты самостоятельно написали C-компилятор, способный собрать Linux</title>
      <link>https://tproger.ru/news/ii-agenty-samostoyatelno-napisali-c-kompilyator--sposobnyj-sobrat</link>
      <comments>https://tproger.ru/news/ii-agenty-samostoyatelno-napisali-c-kompilyator--sposobnyj-sobrat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/ii-agenty-samostoyatelno-napisali-c-kompilyator--sposobnyj-sobrat</guid>
      <description><![CDATA[<p>ИИ-агенты Anthropic самостоятельно создали C-компилятор на Rust, способный собирать Linux 6.9, показав пределы автономной разработки</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/ii-agenty-samostoyatelno-napisali-c-kompilyator--sposobnyj-sobrat">ИИ-агенты самостоятельно написали C-компилятор, способный собрать Linux</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[ARM]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 06 Feb 2026 05:03:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>Исследователь Anthropic Николас Карлини <a href="https://www.anthropic.com/engineering/building-c-compiler">рассказал</a> об эксперименте, в ходе которого группа ИИ-агентов без постоянного участия человека написала полноценный <b>C-компилятор</b>, способный собрать ядро Linux.</p><p>Компилятор написан на Rust, насчитывает <b>около 100 000 строк кода</b> и может собирать Linux 6.9 для архитектур x86, ARM и RISC-V.</p><h2>Как это вообще произошло</h2><p>В эксперименте использовалась модель <b>Claude Opus 4.6</b>, запущенная в режиме так называемых agent teams. Это подход, при котором несколько экземпляров ИИ работают параллельно над одним репозиторием и сами решают, какие задачи брать дальше.</p><p>Всего в проекте одновременно работали <b>16 агентов</b>, каждый из которых запускался в отдельном контейнере и синхронизировался через Git.</p><p>Чтобы агенты не мешали друг другу, они «блокировали» задачи с помощью файлов-локов — если один агент уже взялся за парсинг if, другой был вынужден выбрать другую часть компилятора.</p><p>Процесс длился почти две недели и включал <b>около 2000 сессий Claude Code</b>. Общая стоимость эксперимента составила <b>примерно $20 000</b>.</p><h2>Что умеет получившийся компилятор</h2><p>На выходе получился рабочий, хоть и экспериментальный инструмент:</p><ul><li>собирает Linux 6.9;</li><li>компилирует крупные проекты вроде SQLite, Redis, FFmpeg и QEMU;</li><li>проходит около 99% тестов из GCC torture test suite;</li><li>способен скомпилировать и запустить DOOM — неофициальный, но показательный бенчмарк.</li></ul><p>Важный момент: у ИИ не было доступа к интернету, то есть делалось в рамках имеющейся «базы знаний» модели.</p><h2>Где начинаются ограничения</h2><p>Несмотря на впечатляющий результат, компилятор далек от промышленного использования:</p><ul><li>нет собственного ассемблера и линковщика — они частично заимствуются у GCC;</li><li>кодовая база нестабильна: новые изменения часто ломают старые части;</li><li>16-битный x86-код (нужный для загрузки Linux) реализован «читерски» — через вызов GCC.</li></ul><p>Сами авторы также подчеркнули, что модель <b>уперлась в потолок своих возможностей</b> — дальнейшее развитие компилятора становится все менее предсказуемым.</p>]]></content:encoded>
    </item>
    <item>
      <title>Авторы Tor признали свое шифрование небезопасным. Браузер переходит на CGO вместо tor1</title>
      <link>https://tproger.ru/news/avtory-tor-priznali-svoe-wifrovanie-nebezopasnym--brauzer-perehodit-na-cgo-vmesto-tor1</link>
      <comments>https://tproger.ru/news/avtory-tor-priznali-svoe-wifrovanie-nebezopasnym--brauzer-perehodit-na-cgo-vmesto-tor1?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/avtory-tor-priznali-svoe-wifrovanie-nebezopasnym--brauzer-perehodit-na-cgo-vmesto-tor1</guid>
      <description><![CDATA[<p>Tor отказался от устаревшего шифрования tor1 и переходит на новый алгоритм CGO, повышающий анонимность за счет сильнеей защиты и обновления ключей</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/avtory-tor-priznali-svoe-wifrovanie-nebezopasnym--brauzer-perehodit-na-cgo-vmesto-tor1">Авторы Tor признали свое шифрование небезопасным. Браузер переходит на CGO вместо tor1</a>»</p>]]></description>
      <category><![CDATA[Криптография]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 26 Nov 2025 04:10:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Команда <b>Tor</b> официально <a href="https://www.neowin.net/news/tor-network-beefs-up-weak-relay-encryption-method-reducing-attack-vector/">признала</a>: старый метод шифрования трафика <b>tor1</b> больше не обеспечивает достаточную защиту.</p><p>Из-за накопившихся уязвимостей проект переходит на новый алгоритм — <b>Counter Galois Onion </b>(<b>CGO</b>). Он уже <b>внедрен в Arti (реализацию Tor на Rust)</b> и <b>в классическую C-реализацию</b>.</p><h2>Почему tor1 небезопасен</h2><p>Tor1 использует режим AES-CTR. Он достаточно быстрый, но одновременно с этим и уязвимый к ряду атак. Авторы выделяют <b>три ключевые проблемы</b>:</p><ul><li><b>Тегирование трафика (tagging attacks).</b> Отсутствие hop-by-hop аутентификации делает поток ячеек изменяемым. Вмешавшись, атакующий может деанонимизировать пользователя.</li><li><b>Нет мгновенной прямой секретности.</b> Одни и те же ключи живут весь срок цепочки. Получив ключ, злоумышленник способен расшифровать все предыдущие данные.</li><li><b>Слабая аутентификация.</b> Подпись была всего 4 байта на SHA-1 — это 1 шанс из 4 млрд пройти незамеченным. Для криптографии — ничтожно мало.</li></ul><h2>Что меняет новый CGO</h2><p>CGO решает проблемы комплексно. Алгоритм вводит две ключевых идеи:</p><ol><li><b>Irreversible Update.</b> Ключи обновляются при каждом новом сообщении и старые версии невозможно восстановить. Это дает мгновенную «совершенную прямую секретность».</li><li><b>Wide-block шифрование.</b> Любая попытка изменить хотя бы байт приводит к полной порче расшифровки — атаки тегирования становятся бессмысленны.</li></ol><p>Также <b>MD4</b> заменен на полноценный <b>16-байтный аутентификатор</b>.</p><h2>Когда изменения доберутся до пользователей</h2><p>Tor уже применил CGO в Arti и в реализации на C. Tor Browser, Tails и Orbot постепенно перейдут на новый метод автоматически — пользователю не надо ничего настраивать вручную.</p><p>Для большинства это будет <b>тихое</b>, но <b>крайне важное обновление</b>: впервые за долгие годы Tor получает серьезное усиление защиты на уровне базовой криптографии.</p>]]></content:encoded>
    </item>
    <item>
      <title>В США нашли утерянную ленту с одной из первых версий Unix — спустя 50 лет после релиза</title>
      <link>https://tproger.ru/news/v-swa-nawli-uteryannuyu-lentu-s-odnoj-iz-pervyh-versij-unix---spustya-50-let-posle-reliza</link>
      <comments>https://tproger.ru/news/v-swa-nawli-uteryannuyu-lentu-s-odnoj-iz-pervyh-versij-unix---spustya-50-let-posle-reliza?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-swa-nawli-uteryannuyu-lentu-s-odnoj-iz-pervyh-versij-unix---spustya-50-let-posle-reliza</guid>
      <description><![CDATA[<p>В США нашли магнитную ленту с Unix V4 1973 года. Ее восстанавливают побитово — это может стать важнейшим открытием в истории ОС</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-swa-nawli-uteryannuyu-lentu-s-odnoj-iz-pervyh-versij-unix---spustya-50-let-posle-reliza">В США нашли утерянную ленту с одной из первых версий Unix — спустя 50 лет после релиза</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[unix]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[macOS]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 10 Nov 2025 03:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В хранилище Университета Юты <a href="https://ponderwall.com/index.php/2025/11/09/unix-lost-tape/">нашли</a> <b>магнитную ленту с надписью «UNIX Original From Bell Labs V4»</b>. Предположительно, это четвертая версия Unix, датированная примерно <b>1973 годом</b>.</p><p>Если находка подтвердится, перед нами — одна из старейших копий легендарной операционной системы.</p><h2>Как нашли ленту</h2><p>Ленту обнаружил профессор <b>Роберт Риччи</b> во время уборки в школе вычислительной техники Университета Юты.</p><p>Она лежала в обычной коробке на пыльной полке — без особых отметок. После публикации фотографии находки, на нее обратили внимание историки и инженеры по сохранению ПО.</p><p>Чтобы не повредить артефакт, Риччи передал его в <b>Computer History Museum</b> в Калифорнии. И там, прямо сейчас, ленту осторожно побитово «снимают», не запуская на обычных магнитофонах. Это нужно для того, чтобы не стереть данные.</p><h2>Почему это важно</h2><p>Unix V4 — одна из первых версий, <b>переписанных на языке C</b>. Именно этот шаг сделал систему переносимой между разными машинами. И уже из этого решения выросли <b>Linux</b>, <b>macOS</b> и <b>Android</b>, а архитектура Unix до сих пор лежит в основе большинства современных ОС.</p><p>До последнего считалось, что <b>оригинальная V4 утеряна</b> — в архивах сохранились лишь обрывки кода и фрагменты мануалов.</p><p>Если лента окажется полной, это закроет огромный пробел в истории вычислительной техники.</p><h2>Проблема «цифровой археологии»</h2><p>Ленты 70-х часто страдают от <b>деградации оксидного слоя</b> и «осыпания» носителя. Иногда их приходится буквально запекать при низкой температуре, чтобы стабилизировать материал перед чтением.</p><p>Кроме того, формат данных может быть уникальным — в те годы каждый разработчик использовал свои схемы записи.</p><h2>Почему Unix из Юты — особенный</h2><p>В 1970-х Юта была одним из ключевых узлов ARPANET и первых университетов, получивших Unix по исследовательской лицензии Bell Labs. Местные студенты и инженеры активно модифицировали систему.</p><p>Именно из таких экспериментов, например, позже выросли BSD и многие современные утилиты.</p><h2>Что дальше</h2><p>Эксперты из Computer History Museum планируют оцифровать ленту и, при возможности, опубликовать исходники для исследователей.</p><p>Если восстановление удастся, это будет <b>самое значимое возвращение утерянного программного кода за последние десятилетия</b> — своеобразная «цифровая археология» уровня открытия древнего манускрипта.</p>]]></content:encoded>
    </item>
    <item>
      <title>Rust может стать обязательной зависимостью в Git 3.0</title>
      <link>https://tproger.ru/news/rust-mozhet-stat-obyazatelnoj-zavisimostyu-v-git-3-0</link>
      <comments>https://tproger.ru/news/rust-mozhet-stat-obyazatelnoj-zavisimostyu-v-git-3-0?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/rust-mozhet-stat-obyazatelnoj-zavisimostyu-v-git-3-0</guid>
      <description><![CDATA[<p>Разработчики обсуждают Git 3.0: Rust может стать обязательной зависимостью, улучшая безопасность и скорость, но усложняя сборку</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/rust-mozhet-stat-obyazatelnoj-zavisimostyu-v-git-3-0">Rust может стать обязательной зависимостью в Git 3.0</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Sep 2025 03:42:49 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчики Git обсуждают возможность сделать <b>язык Rust обязательной зависимостью</b> в грядущем обновлении Git 3.0.</p><p>Это означает, что для сборки системы контроля версий потребуется установленный компилятор Rust — как неотъемлемая часть инфраструктуры.</p><h2>Что происходит</h2><p>Предложение активно <a href="https://lore.kernel.org/git/20250904-b4-pks-rust-breaking-change-v1-0-3af1d25e0be9@pks.im/">обсуждается</a> в списке рассылки разработчиков Git. Идея заключается в <b>поэтапной интеграции Rust</b>, аналогично тому, как ранее был внедрен стандарт C99:</p><ul><li>На <b>тестовом этапе</b> Rust останется необязательным, но его использование будет поощряться.</li><li>Начиная с <b>Git 3.0</b>, Rust может стать <b>жесткой зависимостью</b>, необходимой для сборки проекта.</li></ul><h2>Почему Rust?</h2><p>Интеграция Rust началась в <b>Git 2.49</b> (март 2025 года), где появились первые экспериментальные компоненты:</p><ul><li>libgit-sys — низкоуровневая обвязка над внутренними C-библиотеками Git.</li><li>libgit — высокоуровневая библиотека для написания компонентов на Rust.</li></ul><p>В июле 2025 года в проект был предложен Rust-патч для утилиты <b>xdiff</b>, который, по замерам, улучшает производительность на <b>5–19%</b>. Именно тогда впервые прозвучала идея сделать Rust обязательным.</p><h2>Но не все так просто</h2><p>Мнения разработчиков Git разделились. Среди <b>основных аргументов «против»</b>:</p><ul><li><b>Ограниченная кросс-платформенность Rust</b> — не все целевые платформы Git в полной мере поддерживаются компилятором rustc.</li><li><b>Увеличение сложности сборки</b> для пользователей и дистрибутивов.</li><li>Опасения, что переход может <b>исключить «редкие» платформы</b> из числа официально поддерживаемых.</li></ul><p>Сторонники же отмечают:</p><ul><li><b>Рост производительности</b>.</li><li>Безопасность и современный инструментарий, которые дает Rust.</li><li>Возможность постепенного переписывания уязвимых и сложных компонентов Git с более надежным управлением памятью.</li></ul><h2>Что дальше</h2><p>Пока решение не принято. Но <b>вопрос об обязательной зависимости Rust будет решаться до релиза Git 3.0</b>, который может состояться в 2026 году.</p><p>Ожидается, что сначала язык будет использоваться в опциональных частях, а затем его статус пересмотрят с учетом зрелости экосистемы и совместимости.</p><p><b>Обязательная поддержка Rust в Git</b> станет важной вехой: Git всегда был проектом, ориентированным на C и минимальные внешние зависимости. Переход к Rust — это потенциальное изменение философии.</p>]]></content:encoded>
    </item>
    <item>
      <title>NVIDIA начала отказываться от C в критичных модулях ради безопасности</title>
      <link>https://tproger.ru/news/nvidia-nachala-otkazyvatsya-ot-c-v-kritichnyh-modulyah-radi-bezopasnosti</link>
      <comments>https://tproger.ru/news/nvidia-nachala-otkazyvatsya-ot-c-v-kritichnyh-modulyah-radi-bezopasnosti?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/nvidia-nachala-otkazyvatsya-ot-c-v-kritichnyh-modulyah-radi-bezopasnosti</guid>
      <description><![CDATA[<p>NVIDIA отказывается от C в критических модулях — компания переходит на формально проверяемый SPARK ради безопасности, стабильности и доверия клиентов</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/nvidia-nachala-otkazyvatsya-ot-c-v-kritichnyh-modulyah-radi-bezopasnosti">NVIDIA начала отказываться от C в критичных модулях ради безопасности</a>»</p>]]></description>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[NVIDIA]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 11 Jun 2025 05:55:56 GMT</pubDate>
      <content:encoded><![CDATA[<p>NVIDIA совместно с AdaCore <a href="https://blog.adacore.com/nvidia-security-team-what-if-we-just-stopped-using-c">опубликовала</a> кейс, который показывает: компания активно внедряет <b>формально верифицированный код на языке SPARK</b> вместо традиционного C в критически важных модулях.</p><p>Причина — невозможность гарантировать безопасность через тестирование.</p><blockquote><i>Тестировать безопасность невозможно. Нельзя понять, когда ты действительно закончил</i></blockquote><h2>Почему C больше не устраивает</h2><p>На фоне усиления киберугроз, в NVIDIA начали пересматривать подходы к разработке и верификации ПО.</p><p>Тестирование, считают в компании, не может гарантировать безопасность — оно дает понимание качества функциональности, но не защищенности. Поэтому ставка была сделана на <b>доказуемость поведения кода</b> — через формальную верификацию.</p><h2>Что такое SPARK и как его внедрили</h2><p>SPARK — это строго типизированный, безопасный для памяти подмножество языка Ada, предназначенный для написания кода, который можно формально верифицировать. Такие программы можно математически доказать на предмет корректности, отсутствия ошибок и уязвимостей — задолго до запуска.</p><p>Еще в 2018 году NVIDIA провела proof-of-concept: две низкоуровневые, чувствительные к безопасности C-программы были переписаны на SPARK за три месяца. Итоги оказались настолько успешными, что спустя несколько лет:</p><ul><li>в SPARK пишутся <b>целые модули коммерческих продуктов</b> NVIDIA;</li><li><b>обучено более 50 разработчиков</b>;</li><li>верификация значительно упростила <b>процессы аудита</b> и укрепила доверие клиентов.</li></ul><p><i>«Мы не просто запустили инструмент поиска багов — мы формально верифицировали этот код. Это сильно повышает доверие со стороны клиентов»</i>, — отмечается в кейсе.</p><h2>Возражения скептиков развеялись</h2><p>Переход с C на SPARK изначально вызывал сомнения внутри компании. Однако практический опыт показал:</p><ul><li><b>производительность не упала</b>: «разницы с C не заметили», — признались разработчики;</li><li><b>формальная верификация сократила затраты на аудиты</b>;</li><li><b>некоторые изначальные критики стали активными сторонниками</b> подхода.</li></ul><h2>Что дальше</h2><p>Хотя SPARK пока используется точечно, его уже применяют в чувствительных к безопасности частях — там, где традиционные языки и методы верификации не дают нужного уровня уверенности. NVIDIA делает ставку на <b>переход от тестов к доказательствам</b>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Разработчик 20 лет писал на Си и только сейчас узнал про макрос UINT32_MAX</title>
      <link>https://tproger.ru/news/razrabotchik-20-let-pisal-na-si-i-tolko-sejchas-uznal-pro-makros-uint32-max</link>
      <comments>https://tproger.ru/news/razrabotchik-20-let-pisal-na-si-i-tolko-sejchas-uznal-pro-makros-uint32-max?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/razrabotchik-20-let-pisal-na-si-i-tolko-sejchas-uznal-pro-makros-uint32-max</guid>
      <description><![CDATA[<p>Разработчик с 20-летним стажем только недавно узнал о макросе UINT32_MAX — напоминание, что даже в Cи всегда есть чему удивляться</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/razrabotchik-20-let-pisal-na-si-i-tolko-sejchas-uznal-pro-makros-uint32-max">Разработчик 20 лет писал на Си и только сейчас узнал про макрос UINT32_MAX</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 17 Apr 2025 06:05:25 GMT</pubDate>
      <content:encoded><![CDATA[<p>Инженер с 20-летним стажем в программировании на Си <a href="https://subethasoftware.com/2024/12/09/c-has-its-limits-if-you-know-where-to-look/">рассказал</a>, как только недавно узнал о существовании макроса UINT32_MAX.</p><p>Больше новостей — в нашем тг-канале «<a href="https://t.me/your_tech">Представляешь»</a></p><p>Казалось бы, элементарная вещь — но даже опытные разработчики могут упустить полезные возможности языка, особенно если «учились Си» ещё во времена K&amp;R и переходили к ANSI-C уже на лету.</p><p>В своём блоге он вспоминает, как на старых компьютерах int был не 32-битным, как сегодня, а 16-битным. На Radio Shack CoCo int вмещал значения до 65535, а на Commodore Amiga, возможно, уже был 32-битным. Именно из-за таких несостыковок переносимость кода между платформами становилась настоящим испытанием.</p><h2>От самодельных типов к стандарту</h2><p>Чтобы справиться с неопределенностью, разные разработчики создавали собственные типы: u_int32, I16, U32 и так далее. Позже появились стандартизированные stdint.h и limits.h, которые ввели чёткие типы (uint32_t, int16_t) и константы вроде INT_MAX и UINT_MAX.</p><p>Наш герой знал про эти макросы и успешно использовал их. Но, как выяснилось, он упустил одну вещь: stdint.h тоже содержит свои пределы — UINT32_MAX, INT64_MIN, INT8_MAX и десятки других. Эти макросы позволяют писать ещё более надёжный и переносимый код, особенно когда важно жёстко фиксировать размер чисел.</p><h2>Код, который всегда работает</h2><p>До недавнего времени программист вручную писал значения вроде 4294967295 для uint32_t — но теперь он просто использует UINT32_MAX. Это не только читаемо, но и работает на любой платформе, где uint32_t определён.</p><p>КОД</p><p>С signed-типами — аналогично: INT32_MAX, INT16_MIN и так далее. Стандарт Си делает всё это доступным уже давно — просто нужно об этом знать.</p><h2>Урок: даже в Си есть чему удивляться</h2><p>Автор оригинального материала признался: он просто не получил «меморандум» о появлении этих макросов в stdint.h. А ведь они могли сэкономить ему часы — если не годы — возни с ручным вводом чисел и багами на разных архитектурах.</p><p>Мораль проста: даже если ты 20 лет пишешь на Си — всегда найдётся что-то новое. И хорошо, когда язык даёт инструменты, которые делают код чище и безопаснее.</p>]]></content:encoded>
    </item>
    <item>
      <title>ИИ llama2.c от основателя OpenAI запустили на 20-летнем ноутбуке Apple PowerBook G4</title>
      <link>https://tproger.ru/news/--ii-llama2-c-ot-osnovatelya-openai-zapustili-na-20-letnem-noutbuke-apple-powerbook-g4</link>
      <comments>https://tproger.ru/news/--ii-llama2-c-ot-osnovatelya-openai-zapustili-na-20-letnem-noutbuke-apple-powerbook-g4?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/--ii-llama2-c-ot-osnovatelya-openai-zapustili-na-20-letnem-noutbuke-apple-powerbook-g4</guid>
      <description><![CDATA[<p>Llama 2 на 20-летнем PowerBook G4: как llama2.c от сооснователя OpenAI запускает нейросети без GPU и библиотек даже на старом Mac</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/--ii-llama2-c-ot-osnovatelya-openai-zapustili-na-20-letnem-noutbuke-apple-powerbook-g4">ИИ llama2.c от основателя OpenAI запустили на 20-летнем ноутбуке Apple PowerBook G4</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 26 Mar 2025 04:31:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>Энтузиаст <a href="http://www.theresistornetwork.com/2025/03/thinking-different-thinking-slowly-llms.html?utm_source=ixbtcom">провел</a> эксперимент: <b>запустил LLM на ноутбуке Apple PowerBook G4 2005 года</b>.</p><p>Это устройство с процессором PowerPC 7447B на 1.5 ГГц, 1 ГБ оперативной памяти и 32-битной системой. Тем не менее, ему удалось реализовать <b>инференс модели Llama 2 (110M параметров)</b> — без графических ускорителей и сторонних библиотек.</p><p>В основе проекта —<a href="https://github.com/karpathy/llama2.c"> llama2.c</a> от Андрея Карпати, минималистичная реализация LLM на чистом C. Автор переработал код, оформив его в виде библиотеки с публичным API и поддержкой колбэков, чтобы упростить тестирование и интеграцию.</p><h2>Оптимизации и ограничения</h2><p>Для работы на PowerPC потребовались изменения:</p><ul><li>добавлены обертки для системных функций,</li><li>устранены зависимости от exit,</li><li>реализована поддержка big-endian (в отличие от little-endian в современных системах),</li><li>улучшена обработка ошибок и выделение памяти.</li></ul><p>Основной узкий момент — матричные операции. Именно они занимают большую часть времени при генерации текста. Чтобы ускорить выполнение, автор переписал критическую функцию с использованием <b>SIMD-инструкций AltiVec</b>, доступных в процессорах PowerPC.</p><h2>Результаты</h2><p>Для базовой оценки была использована модель TinyStories (110M). На сервере с процессором Intel Xeon inference шел со скоростью <b>6.91 токенов в секунду</b>. На PowerBook G4 — <b>0.77 токена/сек</b>.</p><p>С учетом возраста и ограничений устройства, результат выглядит убедительно. После внедрения SIMD-оптимизаций скорость увеличилась до <b>0.88 токена/сек</b>.</p><h2>Зачем всё это</h2><p>Эксперимент показывает, что <b>современные ИИ-модели могут быть адаптированы даже под устаревшее оборудование</b>, если архитектура реализации достаточно прозрачна и эффективна. Это не только дань инженерному любопытству, но и практическая демонстрация гибкости минималистичных решений.</p><p>Сам автор отмечает, что на этом этапе проект завершен: <b>возможности 32-битной системы ограничены</b>, а запуск более крупных моделей упирается в нехватку адресуемой памяти.</p><p>Тем не менее, даже этот результат — яркое напоминание о том, что технический прогресс не обязательно требует новейшего железа.</p>]]></content:encoded>
    </item>
    <item>
      <title>Энтузиаст разобрал, насколько сложен «Hello,  World!» на самом деле</title>
      <link>https://tproger.ru/news/--entuziast-razobral--naskolko-slozhen--hello---world---na-samom-dele</link>
      <comments>https://tproger.ru/news/--entuziast-razobral--naskolko-slozhen--hello---world---na-samom-dele?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/--entuziast-razobral--naskolko-slozhen--hello---world---na-samom-dele</guid>
      <description><![CDATA[<p>Разбор программы «Hello, World!» показал скрытую сложность: ELF-структуры, системные вызовы и роль компилятора раскрывают весь процесс</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/--entuziast-razobral--naskolko-slozhen--hello---world---na-samom-dele">Энтузиаст разобрал, насколько сложен «Hello,  World!» на самом деле</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[unix]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 26 Dec 2024 03:37:47 GMT</pubDate>
      <content:encoded><![CDATA[<p>Энтузиаст разобрал, насколько сложной на самом деле является программа «Hello, World!».</p><p>В своём материале он <a href="https://4zm.org/2024/12/25/a-simple-elf.html">показал</a>, что даже этот простой пример скрывает множество технических деталей, которые обычно остаются за кадром.</p><p>Так, при компиляции, она превращается в исполняемый файл, полный символов и зависимостей.</p><p>Например, команда objdump -x hello показывает, что даже базовая программа содержит множество секций, таблиц символов и метаданных:</p><h2>Попытка минимализма</h2><p>Чтобы понять работу программы на низком уровне, автор предлагает создать минималистичный исполняемый файл без стандартной библиотеки C.</p><p>Это требует непосредственного написания системных вызовов Linux. Например, вызов write можно реализовать напрямую:</p><h2>Разбор структуры ELF-файла</h2><p>Статья подробно объясняет структуру ELF (Executable and Linkable Format) — стандартного формата для Unix-систем.</p><p>Заголовки ELF, секции и сегменты взаимодействуют друг с другом для создания исполняемого файла.</p><p>Например, заголовок ELF содержит ссылки на таблицы символов и разделы, такие как .text (код программы) и .data (данные).</p><h2>Линкер и оптимизация</h2><p>Автор также разбирает использование кастомных скриптов линковки для создания минималистичных исполняемых файлов.</p><p>Например, с помощью линкера ld можно исключить ненужные зависимости и сократить размер программы.</p><h2>Выводы</h2><p>Как оказалось, даже простая программа «Hello, World!» скрывает сложность, связанную с взаимодействием компилятора, линкера и операционной системы.</p><p>Материал автора в очередной раз подчеркнул важность понимания базовых элементов программного обеспечения и их влияния на процесс выполнения программ.</p>]]></content:encoded>
    </item>
    <item>
      <title>Стартует батл языков программирования 2023</title>
      <link>https://tproger.ru/articles/startuet-batl-yazykov-programmirovaniya-2023</link>
      <comments>https://tproger.ru/articles/startuet-batl-yazykov-programmirovaniya-2023?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Рафаил Агазода]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/startuet-batl-yazykov-programmirovaniya-2023</guid>
      <description><![CDATA[<p>Стартует турнир за звание лучшего языка программирования в 2023 году среди читателей Tproger. Кто же победит в этом году?</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/startuet-batl-yazykov-programmirovaniya-2023">Стартует батл языков программирования 2023</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[Swift]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[BASIC]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Kotlin]]></category>
      <category><![CDATA[Pascal]]></category>
      <category><![CDATA[Dart]]></category>
      <category><![CDATA[Лучший язык 2023]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 18 Dec 2023 08:27:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>Подходит к концу 2023 год, а это значит, пора подвести его итоги и запустить традиционный батл за звание лучшего языка программирования на Tproger.</p><p>Мы уже проводили батл в прошлых <a href="https://tproger.ru/articles/battl-jazykov-programmirovanija-2022-zavershilsja">2020</a>, <a href="https://tproger.ru/articles/battl-jazykov-programmirovanija-2021-zavershilsja">2021</a> и <a href="https://tproger.ru/articles/battl-jazykov-programmirovanija-2022-zavershilsja-2">2022</a> годах: первые два раза в голосовании победил Python, а в прошлом году — C#.</p><p>Вот, кто поборется за звание лучшего языка в 2023 году:</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-12-18/7e3c300f-7dab-486d-af02-360ba8dc5952.png" alt="" /></figure><p>Правила батла остаются прежними:</p><ol><li>В батле участвует 16 языков программирования.</li><li>Ежедневно соревнуются две пары.</li><li>За любимый язык можно проголосовать в течение 24 часов.</li><li>Пары составляются рандомно, так что выбирайте язык, который субъективно нравится больше.</li><li>В финале мы определим тройку победителей.</li><li>Старт — 19 декабря, финал — 26 декабря.</li></ol><p>Примечание Сохраните эту запись в закладки: сюда мы добавим ссылки на все раунды батла во время голосования.</p><ol><li><a href="https://tproger.ru/articles/nachalsya-battl-yazykov-programmirovaniya-2023">Первый раунд</a></li><li><a href="https://tproger.ru/articles/vtoroj-raund-bitvy-yazykov-programmirovaniya-v-2023-godu">Второй раунд</a></li><li><a href="https://tproger.ru/articles/tretij-raund-bitvy-yazykov-programmirovaniya-v-2023-godu">Третий раунд</a></li><li><a href="https://tproger.ru/articles/chetvyortyj-raund-bitvy-yazykov-programmirovaniya-v-2023-godu">Четвёртый раунд</a></li><li><a href="https://tproger.ru/articles/pyatyj-raund-bitvy-yazykov-programmirovaniya-v-2023-godu">Пятый раунд</a></li><li><a href="https://tproger.ru/articles/westoj-raund-bitvy-yazykov-programmirovaniya-v-2023-godu">Шестой раунд</a></li><li><a href="https://tproger.ru/articles/polufinal-bitvy-yazykov-programmirovaniya-v-2023-godu">Полуфинал</a></li><li><a href="https://tproger.ru/articles/final-bitvy-yazykov-programmirovaniya-v-2023-godu">Финал</a></li><li><a href="https://tproger.ru/articles/batl-yazykov-programmirovaniya-2023-zaverwilsya">Результаты</a></li></ol><p>Также подпишитесь на тэг <a href="https://tproger.ru/tag/toplang2023">Лучший язык 2023</a>. Тогда новые раунды батла появятся в вашей личной ленте, а вам будут приходить уведомления об их появлении.</p><p>Старт уже завтра — 19 декабря в 11:00 МСК. Следите, участвуйте, голосуйте!</p>]]></content:encoded>
    </item>
    <item>
      <title>История C++ с 1953 года от FLOW-MATIC и Fortran до языка Си и Cfront</title>
      <link>https://tproger.ru/articles/istoriya-cpp-s-1953-goda</link>
      <comments>https://tproger.ru/articles/istoriya-cpp-s-1953-goda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Рафаил Агазода]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/istoriya-cpp-s-1953-goda</guid>
      <description><![CDATA[<p>Рассказываем о долгом эволюционном пути языков программирования, который привел к появлению C++, от FLOW-MATIC и ALGOL до Cfront.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/istoriya-cpp-s-1953-goda">История C++ с 1953 года от FLOW-MATIC и Fortran до языка Си и Cfront</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[История IT]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 21 Sep 2023 11:40:55 GMT</pubDate>
      <content:encoded><![CDATA[<p>Язык C++ разработал датский программист Бьерн Страуструп, это известный факт. Но что, если копнуть глубже и попытаться разобраться, где находится стартовая точка эволюции языков программирования, которая привела к появлению C++, и какой эволюционный путь прошли языки?</p><p>В этой статье рассказываем, как бизнес в 1950 годах появлиял на развитие языков программирования, какие шаги проделал ALGOL перед тем, как превратился в язык Си, и как языки проделали долгий и витиеватый путь от упрощения к усложнению, и наоборот.</p><h2>Как началась гонка языков программирования между Грейс Хоппер и Джоном Бэкусом</h2><p>В 1953 году математик Грейс Хоппер работала в компании Remington Rand, под началом которой она когда-то выпустила первый в мире компилятор «A Compiler».</p><p>Хоппер уже была известным программистом, поэтому корпорация поставила перед ней новую задачу: облегчить бизнесменам, которые использовали компьютеры, работу с ЭВМ.</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-09-21/4358698c-ece5-47c2-b9c3-b5953130acfa.jpeg" alt="" /><figcaption>Грейс Хоппер</figcaption></figure><p>Хоппер решила, что проще всего будет научить бизнесменов программировать, но в Remington Rand ей отказали: это было бы слишком дорого и долго. И вообще, у бизнесменов нет времени учиться математике, разбирать перфокарты, и так далее. Тогда Грейс Хоппер поняла, что вместо того, чтобы заучивать математические формулы, лучшим способом будет использовать слова из английского языка, с помощью которых можно было бы программировать.</p><p>В Remington Rand снова были недовольны: мол, Грейс Хоппер снова выдумала слишком сложную систему, которая ещё и потребует больше компьютерных ресурсов. Однако профессор математики из Гарварда не сдалась, и в 1955 году представила прототип языка программирования FLOW-MATIC.</p><p>FLOW-MATIC представлял собой декларативный язык программирования, который разрабатывался для автоматизации бизнес-процессов. Для описания вычислений или обработки данных использовались ключевые слова, такие как “SUM” (сумма) или “COMPUTE” (вычисление). FLOW-MATIC также включал возможность работы с переменными данных и логическими условиями, что делало его гибким для разработки различных бизнес-приложений.</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-09-21/0a47be3c-1cc1-45ea-97d5-0997258f7d11.jpeg" alt="" /><figcaption>Документация к FLOW-MATIC</figcaption></figure><p>Обо всех новинках на рынке развивающихся ЭВМ программисты узнавали из ежемесячных профильных журналов, среди которых был “The Communications of the Association for Computing Machinery”. Работа Грейс Хоппер и её команды также не осталась незамеченной.</p><p>В это же время математик Джон Бэкус, который работал в IBM, написал руководству письмо, в котором предложил разработать совершенно другой язык программирования, полностью ориентированный на математические формулы. Дело в том, что сложные формулы было трудно перенести в код ассемблера без ошибок.</p><p>Надо отметить, что Бэкус тоже был известным математиком, который в начале 50-х создал интерпретатор для кода, поэтому предложение одобрили.</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-09-21/48adb027-f706-4907-a502-c6ff07df4699.jpeg" alt="" /><figcaption>Джон Бэкус</figcaption></figure><p>В итоге в конце 1954 года была составлена первая спецификация The IBM Mathematical Formula Translating System.</p><p>Тут началась гонка языков программирования. Хоппер пыталась сделать компьютеры более дружелюбными для бизнес-пользователей, а Бэкус ломал голову над тем, как сделать компьютеры более дружелюбными для математиков.</p><h2>Появление ALGOL и его эволюция в язык BСPL</h2><p>Примерно к 1958 году Association for Computing Machinery совместно с немецким Обществом прикладной математики и механики (Gesellschaft für Angewandte Mathematik und Mechanik) создала рабочую группу, которая должна была создать “универсальный” язык программирования.</p><p>В мае-июне 1958 года в Цюрихе был организован форум, на котором обсуждался вопрос о создании Международного алгоритмического языка или IAL, название которого со временем трансформировалось в ALGOrithmic Language, то есть ALGOL.</p><p>Как это касается героев нашей статьи? Джон Бэкус тоже был в команде ACM по разработке ALGOL, но в это же время он работал над другим языком программирования — FORTRAN. Грейс Хоппер, которую на форум ACM не позвали, в то время работала над COBOL. В общем, Бэкус и Хоппер, как и в ситуации с компилятором и интерпретатором, занимались схожими проблемами, хотя их пути снова не пересеклись.</p><p>Команде ACM удалось выпустить ALGOL, но у него было множество серьезных недостатков. Большинство из них исправили в ALGOL-60, который стал чем-то вроде колыбели для многих других языков программирования. По словам Тони Хоара, разработчика алгоритма «быстрой сортировки», ALGOL-60 был лучшим языком по сравнению со многими своими преемниками.</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-09-21/6afabf48-f7a8-476b-8ba1-bddf37f6c567.jpeg" alt="" /><figcaption>Первая документация к ALGOL-60</figcaption></figure><p>В начале 60-х годов в Кембридже и в Университетском колледже Лондона ALGOL-60 все же были недовольны. Ученые объединились и создали CPL – Combined Programming Language (или Cambridge Plus London, есть и такая версия).</p><p>В отличие от ALGOL-60, который был минималистичным и полагался на элегантный дизайн для решения сложных задач, CPL предоставлял больше инструментов для решения проблем. Во многом CPL заимствовал достоинства FORTRAN, COBOL и SNOBOL и интегрировал их в ALGOL.</p><p>Однако CPL требовала значительных вычислительных ресурсов, которые надо было постоянно поддерживать и расширять. Это значит, конечно, что для программирования на CPL надо было постоянно тратиться на дорогущее железо.</p><p>К 1967 году программистам это совсем надоело, поэтому Мартин Ричардс из Кембриджа предложил снова упростить CPL. Если в прошлый раз CPL был осложнённым языком ALGOL, то теперь Ричардс предложил выбросить как можно больше компонентов от него же.</p><p>Следите за руками: сперва Хоппер и Бэкус начали создавать простые языки программирования, потом на основе их разработок был создан язык посложнее, то есть ALGOL. Потом на основе ALGOL появился ещё один язык посложнее, а теперь снова появилась потребность в том, чтобы упростить разработку.</p><p>В общем, программистам снова нужен был простой язык, который был бы более <i>basic</i>. Так появился Basic Combined Programming Language.</p><h2>Как язык программирования BCPL стал языком B</h2><p>Basic Combined Programming Language или BCPL был прекрасен. На нём было удобно писать, код можно было легко переносить, а претензий к программам вовсе не было. Код BCPL учитывал основные типы архитектур ЭВМ того времени, поэтому он отлично подходил для множества компьютеров.</p><p>Вот Hello World на BCLP:</p><p>Всё испортила эволюция компьютеров. Сотрудник Bell Labs Кен Томпсон обнаружил, что BCPL с её ориентацией на машинные слова плохо подходит для грядущей волны компьютерных систем с байтовой адресацией.</p><p>К примеру, в его лаборатории стоял новенький компьютер PDP-11, и BCPL на нём работал плохо. Томпсон решил переделать BCPL, превратив его в BCPL-lite. От первоначального языка программирования осталась примерно четверть, поэтому и от его названия была отобрана только одна буква из четырёх — буква B из BCLP.</p><p>Язык B был вполне успешным: он был похож на BCPL, но вернул возможности ALGOL-60 по работе с типами данных. Томпсон хотел создать “семантику BCPL с большим количеством синтаксиса SMALGOL”.</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-09-21/d078e177-b6b0-405e-977b-4fedd04e60f4.jpeg" alt="" /><figcaption>Деннис Ритчи и Кен Томпсон</figcaption></figure><p>Начиная с 1972 года, коллега Томпсона по имени Деннис Ритчи решил проапгрейдить B. Язык стал универсальнее, и теперь он подходил как для написания приложений, так и для написания системного кода.</p><p>Кроме того, новый язык на основе B учитывал разнообразие типов появляющихся компьютеров. Около 1974 года Ритчи закончил работу над языком, который был следующим этапом эволюции после B. Конечно же, он назвал его C.</p><h2>Появление языков C и C++</h2><p>Язык C быстро стал универсальным языком в разработке систем и во многих исследованиях в IT. Эту нишу он занимал очень, очень долго. Язык Си стал инструментом, который использовали и для обучения, и для создания очень сложного и производительного кода.</p><p>Си не менялся до тех пор, пока один датчанин по имени Бьерн Страуструп не принялся за написание докторской диссертации. В скандинавских странах широкой популярностью пользовался язык Simula, разработанный норвежцами. Страуструп решил объединить возможности Simula (в частности, наследование, сильную типизацию и инлайнинг) с языком Си.</p><p>Дело в том, что Simula был очень медленным языком, а BCPL была слишком сложной для написания высокоуровневых программ.</p><p>В рамках докторской диссертации Страуструп решил создать инструмент, который был бы производительным, но при этом обеспечивал абстракцию. Его первой разработкой стал C with Classes.</p><p>В 1982 году он решил доработать C with Classes, чтобы язык мог работать над проблемой распределенных вычислений. Так появился C++.</p><p>Изначально Cpp не был полноценным языком. Это был пакет препроцессоров для языка C. Первый публичный релиз 1985 года, Cfront 1.0, был довольно приличным, но чтобы пользоваться им, надо было быть экспертом в C, чтобы не сломать свой же код.</p><p>К 1987 году GCC 1.15.3 начал поддерживать C++, а в 1989 году появился Cfront 2.0, который был гораздо лучше первой версии пакета.</p><p>Тем временем, Международная конференция по стандартизации стала набирать популярность, и в 1990 году был создан комитет ANSI C++, а в 1991 году – комитет ISO C++. В итоге появились C++98/03, затем C++11, затем C++14, C++17, C++20, и так далее.</p><h2>Заключение</h2><p>Вся эта длинная история началась с того, что людям просто не хотелось учить новое. Эта потребность бизнеса в простом решении в середине прошлого века привела к тому, что величайшие математики века раз за разом совершенствовали языки программирования. В конечном итоге, это привело к появлению C++.</p><p>Сперва они создали простой язык, затем усложнили его, затем снова упростили, затем снова усложнили, затем снова упростили, немного усовершенствовали, и снова усложнили.</p><p>Сколько еще раз нам придется наблюдать этот процесс и во что превратится C++ в течение следующих пятидесяти лет?</p>]]></content:encoded>
    </item>
    <item>
      <title>Почему Линус Торвальдс ненавидит C++</title>
      <link>https://tproger.ru/articles/pochemu-linus-torvalds-nenavidit-s</link>
      <comments>https://tproger.ru/articles/pochemu-linus-torvalds-nenavidit-s?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Рафаил Агазода]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/pochemu-linus-torvalds-nenavidit-s</guid>
      <description><![CDATA[<p>Линус Торвальдс признается, что ненавидит C++, а программистов на этом языке он оскорбляет. Разбираемся, в чем заключается причина ненависти.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/pochemu-linus-torvalds-nenavidit-s">Почему Линус Торвальдс ненавидит C++</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Операционные системы]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 12 Sep 2023 11:03:10 GMT</pubDate>
      <content:encoded><![CDATA[<p>В 2007 году пользователь Дмитрий Какурин написал письмо Линусу Торвальдсу, в котором спросил программиста, почему тот использует чистый Си вместо того, чтобы написать все на C++. Само использование чистого Си Дмитрий Какурин назвал емким словом bullshit.</p><p>В ответ Линус Торвальдс поделился своим мнением: bullshit — это сам Какурин, C++ — это ужасный язык, на котором кодеры генерируют, мягко говоря, «нечистоты», а программистов C++ вовсе не стоит допускать до Linux.</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-09-12/f70bc826-3ed6-4e64-94de-81744039a0a5.png" alt="" /></figure><p>После откровенных оскорблений Торвальдс перешел к аргументам.</p><h2>Позиция Линуса Торвальдса относительно C++</h2><p>В первую очередь, Линус говорит, что использование C++ неизменно приводит программиста к плохим решениям вроде использования библиотек STL или Boost, которые считаются прекрасными.</p><p>Однако на деле, по мнению Линуса, они постоянно ломаются, отладка кода становится испытанием, а сам код нестабильный и не портируемый.</p><p>Также Торвальдс заявил, что код на C++ построен на абстракциях, которые не работают как следует. Программист может легко обнаружить, что использованная им абстракция неэффективна, и захочет заменить ее, но для этого ему потребуется переписать все приложение.</p><p>Если же программист захочет написать хорошее, эффективное и портируемое приложение на C++, он будет ограничен рамками, которые уже хорошо реализованы на языке Си.</p><p>Кроме того, использование Си страхует программистов от ошибок, и они не смогут «облажаться» на проекте, а сам язык учит кодеров разбираться в низкоуровневых проблемах. По версии Торвальдса, сплошные плюсы.</p><p>Линус признался, что в 1992 году они уже пытались использовать C++ для написания Linux. С тех пор, по его мнению, мало что изменилось.</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-09-12/6867ce21-a60b-4aae-8b31-7e7de6134578.jpeg" alt="" /><figcaption>Линус Торвальдс в 1994 году. Должно быть, этот очаровательный молодой человек уже пишет оскорбительные вещи про C++.</figcaption></figure><p>Компиляторы C++ все так же не вызывают доверия, а обработка исключений в них вообще не работает.</p><p>Еще C++ скрывает потребление ресурсов, поэтому использовать его для написания ОС Линус считает невероятно глупой затеей. Зато объектно-ориентированный код можно написать на С без всяких проблем.</p><h2>Позиция защиты C++</h2><p>Линус думает, что ненавидит C++. Но, судя по его комментариям, он вообще не знает C++, а то, что он знает, давно устарело.</p><p>Ранние компиляторы C++ были довольно глючными. Они были не намного хуже, чем компиляторы C, но ошибки в них были разными. При этом компилятор C, который он использовал (gcc), тщательно тестировался на ядре Linux, поэтому он почти никогда не видел в нем ошибок. Зато в компиляторе C++ эти ошибки он мог найти с легкостью.</p><figure><img src="https://media.tproger.ru/user-uploads/48741/2023-09-12/5b324a04-82c7-476e-a7f0-2d84a7282893.png" alt="" /><figcaption>Компилятор Borland C++ 3.1</figcaption></figure><p>C++ был первым популярным объектно-ориентированным языком, а его ранние версии C++ были написаны на Smalltalk со странным синтаксисом. Поэтому ранний C++ работал плохо, и особенно плохо он работал в ядре Linux.</p><p>Похоже, что Линус сделал поспешные выводы, основанные на минимальном анализе. Когда он увидел, что C++ работает не так, как он ожидал, он просто отмахнулся от него, вместо того, чтобы изучить. К примеру, в C NULL может быть типобезопасным, а в C++ для этого нужно использовать nullptr, а не NULL.</p><p>С тем же успехом Линус Торвальдс мог бы заявить, что ненавидит язык суахили, потому что он его не знает.</p><h2>Заключение</h2><p>В целом, Линус Торвальдс прав, и для ядра Linux действительно лучше подойдет низкоуровневый язык Си, а не C++. Но в остальном вся его ненависть сводится к тому, что он попробовал использовать C++ практически на старте языка, и тот ему не понравился.</p><p>Кроме того, стоит помнить, что Линус говорит о C++ в контексте использования языка для написания ядра операционной системы. Этой же позиции придерживаются и другие авторы ОС. Ядра Windows, Linux, iOS, MacOS, FreeBSD написаны на языке Си.</p><p>А что о C++ думаете вы? Справедливы ли нападки Торвальдса?</p>]]></content:encoded>
    </item>
    <item>
      <title>Стоит ли изучать С и С++ после Java</title>
      <link>https://tproger.ru/articles/stoit-li-izuchat-s-i-s-posle-java</link>
      <comments>https://tproger.ru/articles/stoit-li-izuchat-s-i-s-posle-java?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дух айтишной эмо школы]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/stoit-li-izuchat-s-i-s-posle-java</guid>
      <description><![CDATA[<p>Разбираемся, зачем переходить с Java на С или С++, зачем учить С-языки и какие плюсы и минусы присущи С и С++ по сравнению с Java.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/stoit-li-izuchat-s-i-s-posle-java">Стоит ли изучать С и С++ после Java</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 01 Sep 2023 09:53:30 GMT</pubDate>
      <content:encoded><![CDATA[<p>Java — отличный язык программирования, который проверен и временем, и количеством программ, которые на нём написаны. Java часто рекомендуют в качестве первого языка программирования, потому что он решает большинство проблем в написании ПО и потому что он максимально понятен.</p><p>Однако у Java есть и некоторые минусы, которые могут натолкнуть вас на мысль о переходе на другой язык программирования.</p><p>В этой статье разбираемся, зачем переходить с Java на С или С++, зачем учить именно С-языки и какие плюсы и минусы присущи С и С++ по сравнению с Java.</p><h2>Зачем переходить на C/C++ после Java</h2><p>За некоторыми исключениями C++ считается чем-то вроде надстройки Java, но это не значит, что при переходе с Java на C++ будет просто: вам нужно будет изучить новые концепции языка и новый синтаксис.</p><p>Основное преимущество C++ заключается в том, что он не обременяет новичка концепциями объектов. Также C++ лучше поддерживает более поздние классы, которые используются в написании операционных систем и построении компиляторов. Написание ОС в Java осложняется тем, что JVM сама по себе является подобием ОС.</p><p>Если вам нужно написать код, который управлял бы железом устройства, изучение байт-кода JVM не рекомендуется: он плохо переводится на язык ассемблера. Код Java “живет” в JVM, которая отрывает программу от железа.</p><p>Java присуща негибкость: например, код отличается многословным синтаксисом, который нелегко сократить. Код на Java, кажется, имеет другой стиль разработки, который поощряет крупные и сложные решения, тогда как более мелкие и простые были бы эффективнее.</p><p>C/C++, с другой стороны, ужасно беспорядочные языки, которые наполнены устаревшими функциями. Хуже того, из-за этого беспорядка можно выстрелить себе в ногу, написав отличный код, но не учтя нюансов его работы, о которых вы никогда и не слышали.</p><p>Однако код на C/C++ более гибкий, и как только вы его изучите, вы поймёте, что можете решить проблему множеством способов. В Java при этом обычно поощряется один способ решения задачи.</p><p>Кроме того, в процессе изучения C/C++ вы научитесь работе с указателями, стеком, производительностью, изучите процесс компиляции и системное программирование.</p><p><b>Резюмируя, вот причины, по которым вам стоит перейти с Java на C/C++:</b></p><ol><li>Вам нужно написать программу, которая тесно взаимодействовала бы с железом.</li><li>Вы хотите изучить низкоуровневый язык программирования.</li><li>Вы хотите следить за последними обновлениями в языках программирования.</li><li>Вам хочется писать на “гибком” языке программирования, который предложил бы несколько решений проблемы.</li><li>Вы хотите писать лаконичный код.</li></ol><h2>Зачем учить С</h2><p>Обычно С предлагают учить перед С++, потому что кажется, что сперва нужно изучить менее развитый язык и понять концепции низкого уровня вроде malloc и free. И, конечно, эта точка зрения имеет право на жизнь.</p><p>К примеру, при изучении С вы сможете понять общие принципы языка, не вдаваясь в сложные концепции вроде классов, объектов, наследования, полиморфизма, шаблонов, обработки исключений и ссылок. Сперва полезнее изучить основные элементы С.</p><p>Ещё один существенный плюс С — его низкоуровневость. Если вы собираетесь писать операционную систему или драйвера для устройств, если вы хотите разрабатывать мобильные приложения, стоит присмотреться к С, а не к С++, потому что первый язык существенно выигрывает в производительности и скорости.</p><p>То же касается и геймдева: если игра требует быстрых вычислений, С станет отличным инструментом.</p><p>Однако у пути от менее развитого языка к более развитому есть существенные минусы. Вы можете обнаружить, что многие выражения C — это худшая версия выражений C++.</p><p>C — это низкоуровневый язык, который будет подталкивать вас к использованию небезопасных абстракций низкого уровня. Если вы сможете соблюдать типовую безопасность, проблем не возникнет.</p><p>Также способ управления памятью в C сильно отличается от C++, даже несмотря на то, что он построен на низкоуровневых абстракциях. Как ни странно, проще понять управление памятью через конструкции std::move() и std::unique_ptr в С++, чем malloc/free в C. Ещё один нюанс низкоуровневого С — сложность массивов.</p><p>Также в C++ есть выражения, которые были заимствованы из более современных языков и которых нет в C.</p><p>Оптимальный вариант — начать обучение с C++, а затем немного поработать с C, чтобы понять нюансы работы низкоуровневого языка.</p><h3>Плюсы в пользу C после Java</h3><ul><li>C — относительно простой язык с меньшим количеством функций, чем в C++.</li><li>Изучение C углубит понимание концепций низкоуровневого программирования, таких как управление памятью и указатели.</li><li>Код C легче переносить на разные платформы.</li></ul><h3>Минусы изучения C после Java</h3><ul><li>В С меньше принципов ООП. C — это процедурный язык, и в нем не так сильно используется объектно-ориентированное программирование (ООП), как в Java или C++.</li><li>В языке C отсутствуют современные функции и библиотеки, аналогичные тем, что уже есть в Java и C++.</li></ul><h2>Зачем учить С++</h2><p>C++ — это язык, который лучше всего для жесткого контроля над управлением памятью. Также здесь играет огромную роль производительность программ.</p><p>С++ отлично подойдёт для высокопроизводительных вычислений, при которых вы не можете позволить себе расходы на память, но вам нужно, чтобы все работало как можно быстрее. C++ лучше подходит для высокопроизводительных численных вычислений, чем Java в целом. При этом учтите, что кривая обучения C++ очень большая.</p><p>Java, с другой стороны, не зависит от платформы и имеет большую поддержку библиотек (синтаксический анализ XML и т. д.). Java — это интерпретируемый язык, с которым вам не нужно беспокоиться об управлении памятью.</p><p>Недостатком Java является относительно плохая настройка производительности. В Java нет особого контроля над распределением памяти, и часто возникает нехватка высокопроизводительных числовых пакетов.</p><p>Что касается синтаксиса, в Java код очень подробный: всё должно быть классом, и каждый класс должен находиться в отдельном файле, и так далее. Однако и синтаксис C++ тоже непрост в изучении, так может быть препятствием в переходу с одного языка на другой.</p><h3>Плюсы в пользу C++ после Java</h3><ul><li>Как и Java, C++ является объектно-ориентированным и поддерживает классы, объекты и наследование.</li><li>C++ предлагает более широкий набор функций, включая низкоуровневые манипуляции с памятью, шаблоны и стандартную библиотеку шаблонов (STL).</li><li>C++ широко используется в разработке игр, системном программировании и приложениях, где производительность критична.</li></ul><h3>Минусы изучения C++ после Java</h3><ul><li>C++ может быть сложнее в изучении из-за обширного набора функций.</li><li>Хотя C++ предлагает контроль над управлением памятью, это также может привести к увеличению количества ошибок.</li></ul><h2>Заключение</h2><p>Эта статья была написана на основе советов опытных программистов, которые больше 10 лет кодят на Java и С-языках. Надеемся, материал получился исчерпывающим и помог вам решить, стоит ли переходить с Java на С и С++.</p><p>Приглашаем вас присоединиться к дискуссии. Какие аргументы в пользу С/С++ мы забыли упомянуть? Или, может быть, есть и другие языки, которые закрывают проблемы Java, но на которые перейти было бы удобнее, чем на С-языки? Напишите в комментариях! 🙂</p>]]></content:encoded>
    </item>
    <item>
      <title>Зачем нужен MISRA C — стандарт с огромным количеством запретов</title>
      <link>https://tproger.ru/articles/zachem-nuzhen-misra-c-standart-s-ogromnym-kolichestvom-zapretov</link>
      <comments>https://tproger.ru/articles/zachem-nuzhen-misra-c-standart-s-ogromnym-kolichestvom-zapretov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Рафаил Агазода]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/zachem-nuzhen-misra-c-standart-s-ogromnym-kolichestvom-zapretov</guid>
      <description><![CDATA[<p>Рассказываем, что такое стандарт MISRA для кода на С и С++, почему в MISRA описана сотня запретов и как применять стандарт в разработке ПО.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/zachem-nuzhen-misra-c-standart-s-ogromnym-kolichestvom-zapretov">Зачем нужен MISRA C — стандарт с огромным количеством запретов</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Безопасный код]]></category>
      <category><![CDATA[Системный анализ]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 11 Aug 2023 11:35:48 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://ru.wikipedia.org/wiki/MISRA_C">MISRA C</a> – это набор промышленных рекомендаций и стандартов, разработанных ассоциацией MISRA (Motor Industry Software Reliability Association) для разработки программного обеспечения на языке Си.</p><p>Стандарт был создан для того, чтобы повысить безопасность и надёжность кода в том случае, когда от его качества зависит жизнь человека. К примеру, MISRA используют в автомобильной отрасли.</p><p>К примеру, представьте, что ваш автомобиль из-за программной ошибки не позвонил в службу спасения. Или самолёт вдруг отказался опустить шасси. Или рентген взял и облучил вас высокой долей радиации. Или робот-хирург отказался работать посреди операции.</p><p>Конечно, эти примеры — донельзя утрированные, но столкнуться с ними в реальной жизни не хотелось бы никому. Именно жёсткий стандарт MISRA позволяет исключить возможность ошибки, которая может стоить жизни.</p><p>MISRA C определяет правила, которым разработчикам следует следовать при написании кода. Каждый год количество правил, по своей сути — запретов, только растёт:</p><ul><li>В MISRA-C:1998 указаны 127 правил: 93 обязательных и 34 рекомендательных.</li><li>В MISRA-C:2004 указано 141 правило: 121 обязательное и 20 рекомендательных.</li><li>В MISRA-C:2012 указаны 143 правила и 16 директив.</li></ul><p>Они включают рекомендации по оформлению, по использованию конструкций языка, предупреждают о потенциальных проблемах вроде неопределенного поведения или возможности ошибок.</p><h2>Как появился MISRA</h2><p>Стандарт MISRA был разработан ассоциацией MISRA (Motor Industry Software Reliability Association) в 1994 году в Великобритании. Изначальная цель стандарта — повысить безопасность и надежность ПО для автомобилей.</p><p>В начале 1990-х годов количество электроники в автомобилях неуклонно росло. Стало очевидно, что некачественный код может быть опасен для пассажира: к примеру, ошибка ПО во время движения может стоить водителю жизни. Чтобы обезопасить пассажиров, и была создана ассоциация MISRA.</p><p>Первый выпущенный стандарт назывался “MISRA Guidelines for the Use of C in Vehicle-Based Software”. Его опубликовали в 1994 году. Он определил правила для использования языка Cи в автомобильном ПО.</p><p>Помимо общих правил вроде оформления кода, первый стандарт включал в себя:</p><ol><li>Правила для управления типами данных, которые запрещали преобразование типов.</li><li>Рекомендации для обработки исключительных ситуаций (exceptions). Рекомендации по использованию операторов try-catch, исключений и т.д.</li><li>Запрет непортативных (non-portable) функций и конструкций, которые могут привести к неправильному поведению или ошибкам при переносе кода на другие платформы или компиляторы.</li><li>Рекомендации и требования к валидации кода и процессу разработки.</li></ol><p>В последующие годы стандарт обновлялся и дополнялся. В 2004 году был выпущен стандарт “MISRA C:2004”, а в 2012 году – стандарт “MISRA C:2012”.</p><p>В 2023 году стандарт снова обновился</p><h2>Где используется MISRA</h2><p>Сегодня стандарт используют почти во всём транспорте — в автомобильной и авиационной отраслях —, в медицине и промышленности. Вот несколько компаний, которые применяют MISRA в разработке ПО:</p><ol><li>Автомобильная промышленность: BMW, Ford, General Motors, Honda, Toyota и Volkswagen.</li><li>Авиационная промышленность: Airbus и Boeing.</li><li>Медицинская техника: Siemens Healthineers, Philips Healthcare и Medtronic.</li><li>Промышленные системы: Schneider Electric и Rockwell Automation.</li></ol><h2>Что запрещено в MISRA</h2><p>Вот несколько примеров того, что запрещено в стандарте MISRA:</p><ol><li>Фрагменты кода не должны быть закомментированы.</li><li>Базовые типы char, int, short, long, float и double не должны использоваться.</li><li>Операнды логических операторов &amp;&amp; или || должны быть первичными выражениями.</li><li>Оператор goto не должен использоваться.</li><li>Заголовочный файл  и функция setlocale не должны использоваться.</li></ol><p>К примеру, вместо char, int, short, long, float и double нужно использовать директиву typedef.</p><p>Неправильный код:</p><p>Правильный код:</p><p>Операнды &amp;&amp; и || должны быть одиночными переменными, константами или выражениями в скобках.</p><p>Неправильный код:</p><p>Правильный код:</p><p>С полным списком правил на русском языке <a href="https://easyelectronics.ru/files/Book/misra_c_rus.pdf">можно ознакомиться по этой ссылке</a>.</p><h2>Как проверять код на соответствие MISRA</h2><p>На рынке есть несколько анализаторов кода, которые проверяют соответствие стандарту MISRA.</p><ol><li><a href="https://pclintplus.com/">PC-lint/FlexeLint</a> — один из самых популярных инструментов статического анализа для языка C и C++. PC-lint/FlexeLint поддерживает проверку соответствия нескольким версиям стандарта MISRA C, включая MISRA C:1999, MISRA C:2004 и MISRA C:2012.</li><li><a href="https://www.mathworks.com/products/polyspace.html">Polyspace</a> — анализатор от MathWorks также поддерживает проверку соответствия стандарту MISRA C. Он помогает отслеживать проблемы вроде неопределенного поведения или использования небезопасных функций.</li><li><a href="https://www.perforce.com/products/klocwork">Klocwork</a> — ещё один популярный инструмент статического анализа, который поддерживает проверку соответствия стандарту MISRA C.</li><li><a href="https://cppcheck.sourceforge.io/">Cppcheck</a> — бесплатный и открытый инструмент статического анализа для C и C++. Изначально он не настроен на проверку соответствия стандарту MISRA, но Cppcheck помогает обнаружить некоторые нарушения.</li></ol><p>Также есть пара компиляторов.</p><ol><li><a href="https://www.iar.com/products/architectures/arm/iar-embedded-workbench-for-arm/">IAR Embedded Workbench</a> — один из наиболее известных компиляторов, который предоставляет мощный статический анализатор для поиска нарушения правил MISRA и предлагает решения для их исправления.</li><li><a href="https://www.ghs.com/products/MULTI_IDE.html">MULTI IDE</a> — интегрированная среда разработки (IDE) с компилятором, поддерживающим стандарт MISRA C. MULTI IDE включает в себя инструменты статического анализа, покрывающие правила MISRA и помогающие в обнаружении потенциальных ошибок.</li></ol><h2>Заключение</h2><p>В заключение, стандарт MISRA C — важный инструмент для повышения качества и безопасности кода, который включает рекомендации и правила для написания надежного и поддерживаемого ПО.</p><p>Но стоит отметить, что соблюдение стандарта не всегда обязательно и зависит от требований проекта. Некоторые компании выбирают свой набор правил, адаптированных под их цели и реалии разработки.</p><p>Соблюдение стандарта MISRA C — это только один из инструментов при разработке безопасного ПО. Он должен быть использован вместе с другими методологиями и практиками вроде тестирования или обзора кода.</p><p>Надеюсь, статья оказалась интересной и полезной. Если вы работаете, к примеру, в разработке ПО для автомобилей, расскажите в комментариях, используете ли вы MISRA в работе. Может быть, есть и другие стандарты, которые на практике популярнее MISRA?</p>]]></content:encoded>
    </item>
    <item>
      <title>Меняем фреймворк юнит-тестирования одной строчкой кода</title>
      <link>https://tproger.ru/articles/menyaem-frejmvork-yunit-testirovaniya-odnoj-strochkoj-koda</link>
      <comments>https://tproger.ru/articles/menyaem-frejmvork-yunit-testirovaniya-odnoj-strochkoj-koda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Елизавета Ржевская]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/menyaem-frejmvork-yunit-testirovaniya-odnoj-strochkoj-koda</guid>
      <description><![CDATA[<p>Как сменить фреймворк для юнит-тестирования на С и С++, если количество самих тестов слишком велико, а писать их заново не хочется.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/menyaem-frejmvork-yunit-testirovaniya-odnoj-strochkoj-koda">Меняем фреймворк юнит-тестирования одной строчкой кода</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Фреймворки и библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 11 Feb 2023 08:15:24 GMT</pubDate>
      <content:encoded><![CDATA[<p>Коротко, о чем статья: использование различных фреймворков юнит-тестирования для поддержки качества кода прошивок микроконтроллеров на языке С/С++, способ миграции на новый фреймворк, если на старом уже написано большое количество тестов.</p><h2>Введение</h2><p>В современной разработке сложно представить себе серьезный проект, в котором не использовались бы практики CI/CD, а код не был бы покрыт юнит-тестами, однако при создании прошивок для микроконтроллеров далеко не каждая команда уделяет время настройке и поддержке этих процессов. При работе над одним из медицинских приборов мы обнаружили, что имеющиеся юнит-тесты покрывают только те части кода, которые отвечают за логику и программные вычисления, но совсем не затрагивают тестирование аппаратных функций. Эта статья про то, почему нужно обязательно тестировать вызовы к HW, почему пришлось менять фреймворк юнит-тестирования и как удалось упростить процесс перехода.</p><h2>Зачем тестировать аппаратные функции?</h2><p>Ответ на этот вопрос очень простой – затем же, зачем и неаппаратные, то есть, чтобы быть уверенным, что код работает именно так, как ожидается. Некоторые разработчики попадают в ловушку, предполагая, что если используются документированные SDK API, то можно целиком на них положиться и не перепроверять их работу. Однако представим себе разработку устройства на стадии подготовки прототипа. В любой момент может быть принято решение об изменении версии SDK или микроконтроллера, и в этом случае точно придется перепроверять работу аппаратных функций. Такие миграции возможны и при разработке очередной версии уже готового устройства, когда кодовая база успела значительно разрастись. А если продукт уже вышел в серийное производство, то понадобится проверка каждого устройства в заводских условиях. Для этого пишутся специальные тестовые прошивки, базой для которых легко может стать набор юнит-тестов для аппаратных функций.</p><p>Еще одна потенциальная проблема – запуск юнит-тестов на ПК недостаточен для проверки правильности вычислений. Из-за различий в аппаратной архитектуре самые обычные операции, например, арифметика чисел с плавающей точкой, могут давать разные результаты.</p><p>Ориентируясь на эти тезисы, мы занялись исправлением ситуации на проекте.</p><h2>Выбираем фреймворк</h2><p>На проекте на тот момент уже использовался популярный фреймворк GoogleTest для юнит-тестирования кода на С++. О его преимуществах говорить не будем, их много, и статья не о них. В нашем случае были важнее его недостатки, а именно – размер собранной библиотеки, который «съедал» солидный кусок из наших скромных 256KB.</p><p>Можно было, конечно, пропатчить код, оставив только используемые куски и сократив, таким образом, размер библиотеки, но это скорее походило на то, что мы используем неподходящий инструмент, чем на хорошее решение. Тем более, что был найден другой, гораздо более простой и легковесный фреймворк Unity (нет, никакого отношения к геймдеву не имеет), состоящий из пары заголовочных файлов и одного С-файла (что будет преимуществом, если проект написан на чистом С). Так как каких-то сложных тестовых сценариев нам писать не требовалось, то для тестирования аппаратных функций мы решили выбрать именно его.</p><p>На этой стадии получалось, что мы используем Unity для SDK API, и GoogleTest для всего остального. Вариант, в целом, рабочий, и в какой-то момент мы даже думали остановиться на нем несмотря на то, что иметь в проекте разные фреймворки для, по сути, одной задачи, это явно перебор. Но переводить уже имеющуюся базу тестов на новый фреймворк никто не горел желанием. Однако вскоре этот вопрос поднялся снова – часть тестов была направлена на проверку корректности вычислений, и требовала дублирования тестов на обоих фреймворках. А это уже было неприемлемо. Пришлось лезть внутрь исходников GoogleTest и смотреть на реализацию используемых тестовых макросов. Довольно быстро стало ясно, что можно написать собственный преобразователь GoogleTest =&gt; Unity, который позволит оставить код имеющихся тестов неизменным.</p><h2>Пишем gtest2unity.h</h2><p>В целом, идея довольно простая – переопределить макросы старого фреймворка собственными, которые используют макросы нового. В этом случае будет достаточно подменить заголовочный файл, не меняя ни строчки кода в тестах.</p><p>Начинаем с простого: устанавливаем соответствия между макросами проверки:</p><p>Что кроется за этими макросами нам не очень интересно, т.к. передаваемые параметры совпадают, и по имени можно определить, что проверки выполняются одинаковые. Оба фреймворка обладают внушительным арсеналом различных проверок, и вполне вероятно, что некоторым не найдется аналога, но для обычных юнит-тестов такой проблемы не возникает.</p><p>Теперь переходим к чуть более сложной части. Что еще используется в имеющихся тестах, связанное с GoogleTest?</p><p>Что ж, тут тоже очевидно, что нужен собственный класс testing::Test, от которого мы сможем наследоваться подобным образом.</p><p>Теперь переходим к последней части, зависимой от GoogleTest:</p><p>Здесь уже приходится обращаться к исходному коду GoogleTest, потому что догадаться, что скрыто за макросом TEST_F, довольно сложно (заинтересованным рекомендую обратиться к гитхабу проекта и изучить макрос GTEST_TEST_ в файле gtest-internal.h). Оказалось, что за TEST_F спрятано довольно много кода, большая часть из которого нам не нужна. Главные пункты, которые нам пришлось адаптировать:</p><p>– каждый тест-кейс – отдельный класс, унаследованный от нашего PumpDriverTests;</p><p>– тело тест-кейса – реализация приватной функции этого класса;</p><p>– нужна функция, которая создаст экземпляр этого класса, а затем последовательно вызовет его методы.</p><p>Сначала определим пару макросов для удобства, чтобы легко получать уникальные имена для наших классов и функций:</p><p>А затем реализуем описанные пункты:</p><p>Вот мы и получили рабочий вариант gtest2unity.h. Теперь для перевода файла с GoogleTest на Unity достаточно простого:</p><p>Ну и, конечно, добавить файлы Unity в систему сборки (например, в CMakeLists.txt). Ошибок компиляции больше нет, и наша работа закончена… или нет? Скомпилировать код без ошибок — это, конечно, хорошо, но сами тесты еще и запустить надо. GoogleTest определяет необходимые методы по умолчанию, но в Unity нужно все делать руками. Программисты, как известно, не очень любят ручную работу, поэтому мы решили написать простой генератор кода запуска тестов.</p><h2>Генерируем test_runner.cpp</h2><p>Запустить тесты с помощью Unity не сложно:</p><p>Над генератором долго не думаем – выбираем Python и вперед! Хардкодим подключение заголовочных файлов и части с UNITY_BEGIN и UNITY_END в локальные строки. Дальше парсим исходники, но и тут все довольно тривиально – находим макрос TEST_F в коде, вытаскиваем его параметры и записываем их в макрос EXTERN_TEST_F_NAME дважды – первый раз перед main() вместе с extern объявлением (даем понять, что сама функция находится в другом файле), второй уже внутри RUN_TEST, чтобы, соответственно, запустить сам тест.</p><p>Собрав информацию обо всех тест-кейсах, генерируем итоговый файл (который также нужно включить в систему сборки). Теперь и компиляция, и линковка, и запуск – все готово к тому, чтобы наши тесты падали при неудачных изменениях кода.</p><h2>Заключение</h2><p>В заключение хочется сказать, что мы ни в коем случае не рекомендуем использовать подобные трюки без крайней необходимости. В нашем случае достаточно было принять во внимание необходимость тестировать SDK API и с самого начала выбрать подходящий фреймворк юнит-тестирования. Однако мы редко встречаемся с идеальными условиями, поэтому стоит иметь ввиду, что иногда можно исправить ситуацию и с таким подходом.</p><p>Несомненно, приведенный код далек от идеала (а тот, который не показан, тем более), но для нашей ситуации его оказалось достаточно, и мы смогли продолжить работу над проектом, теперь уже покрывая тестами весь код.</p>]]></content:encoded>
    </item>
    <item>
      <title>Лучший язык программирования: рейтинг TIOBE 2022</title>
      <link>https://tproger.ru/articles/luchshij-jazyk-programmirovanija-rejting-tiobe-2022</link>
      <comments>https://tproger.ru/articles/luchshij-jazyk-programmirovanija-rejting-tiobe-2022?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Александровна]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/luchshij-jazyk-programmirovanija-rejting-tiobe-2022</guid>
      <description><![CDATA[<p>В этом году рейтинг языков программирования TIOBE удивил тройкой лидеров. Узнайте, какой из языков потеснил Java и вышел в топ-3!</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/luchshij-jazyk-programmirovanija-rejting-tiobe-2022">Лучший язык программирования: рейтинг TIOBE 2022</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Статистика]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Perl]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Kotlin]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 23 Dec 2022 12:35:23 GMT</pubDate>
      <content:encoded><![CDATA[<p>На днях у нас прошёл батл языков программирования 2022, и настало время обратиться к рейтингам TIOBE.</p><p>Напомним, что индекс TIOBE оценивает популярность языков программирования, основываясь на поисковых запросах, которые содержат тот или иной язык. Для формирования индекса используются такие ресурсы, как Google, YouTube, Amazon, Wikipedia, Yahoo!, Bing и Baidu.</p><p>В 2023 году популярность языков изменилась. Какие языки потеряли популярность, а какие — нет, <a href="https://tproger.ru/articles/best-prog-lang-2023">рассказали в этой статье</a>.</p><ol><li>Python, C и C++ соревнуются за звание лучшего языка</li><li>Пара слов о других языках</li><li>Выводы</li></ol><h2>Python, C и C++ соревнуются за звание лучшего языка</h2><p>Именно таковы результаты по состоянию на конец декабря — двадцать языков программирования с наибольшей рыночной долей по версии TIOBE:</p><figure><img src="https://media.tproger.ru/uploads/2022/12/9bcee0e3-9325-45a6-985b-c850cc01a924.jpg" alt="" /></figure><p>Ещё в прошлом году Java уверенно держалась в тройке, но теперь уступила своё место «плюсам». Любопытно, что в последний раз C++ становился лидером рейтинга TIOBE в далёком 2003 году, и это впервые, когда данный язык программирования обошёл Java по поисковым запросам. При этом Java входила в топ-3 свыше двадцати лет, начиная с 2001.</p><p>Уже в следующем месяце мы узнаем имя победителя. Каждый из лидирующей тройки уже занимал первое место по итогам года:</p><ol><li>C++ — 1 раз (2003).</li><li>C — 3 раза (2008, 2017, 2019).</li><li>Python — 5 раз (2007, 2010, 2018, 2020, 2021).</li></ol><h2>Пара слов о других языках</h2><p>Помимо прочего, мы видим, как Kotlin и Julia приближаются к топ-20, JavaScript держится в семёрке, а PHP вырывается в десятку, тогда как в прошлом году занял 12-е место.</p><p>Интересно, что Go поднялся аж на 7 позиций и теперь занял 12-е место рейтинга. Стоит отметить, что по версии GitHub за третий квартал 2022 Golang также находится на четвёртом месте по популярности, обогнав при этом PHP, C, C#, Ruby, TypeScript и JavaScript. Тенденция налицо:</p><figure><img src="https://media.tproger.ru/uploads/2022/12/d6659c61-2e2c-4fa7-8d63-f8121e17b018.jpg" alt="" /></figure><p>На 18-е место рейтинга TIOBE вернулся Perl. Rust удерживает 20 позицию. Что касается Delphi, то он всю осень прыгал туда-сюда:</p><ul><li>сентябрь — 13 место (1.09%);</li><li>октябрь — 18 место (0.85%);</li><li>ноябрь — 14 место (1.08%).</li></ul><p>В декабре же язык опустился на 16 место (0.85%), что соответствует результатам декабря прошлого года.</p><h2>Выводы</h2><p>Разумеется, рейтинг языков программирования 2022 TIOBE сложно назвать объективным, так как он рассматривает лишь один аспект — популярность ЯП в поисковых запросах пользователей. Он не отражает реальный рыночный спрос или количество написанного кода, как это делает GitHub в своих отчётах на основе проектов.</p><p>Тем не менее, индекс TIOBE можно использовать, чтобы проверить, актуальны ли ваши навыки, или принять решение о том, на какой язык программирования можно перейти или какой следует использовать при написании новой программы.</p>]]></content:encoded>
    </item>
    <item>
      <title>Пятый раунд битвы языков программирования 2022</title>
      <link>https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2022</link>
      <comments>https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2022?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Рафаил Агазода]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2022</guid>
      <description><![CDATA[<p>Выбираем лучший язык программирования в 2022 году. В пятом раунде битвы встретились Pascal и Python, C и C#.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2022">Пятый раунд битвы языков программирования 2022</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Pascal]]></category>
      <category><![CDATA[Лучший язык 2022]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 17 Dec 2022 08:00:25 GMT</pubDate>
      <content:encoded><![CDATA[<p>Начинается пятый раунд битвы языков программирования за звание лучшего в 2022 году. В новом раунде встретились:</p><ul><li>Pascal и Python;</li><li>C# и C.</li></ul><p>Четвёртый раунд завершился победой TypeScript над JavaScript и Java над Rust. При этом TypeScript вырвался вперёд с преимуществом всего лишь в 4%.</p><p>Результаты прошлого раунда можно посмотреть <a href="https://tproger.ru/articles/chetvjortyj-raund-bitvy-jazykov-programmirovanija-2022/">здесь</a>.</p><p>Подпишитесь на тег <a href="https://tproger.ru/tag/luchshij-jazyk-2022/">Лучший язык 2022</a> и следите за обновлениями в личной ленте, чтобы не пропустить новые раунды битвы.</p><figure><img src="https://media.tproger.ru/uploads/2022/12/battle_table-3.png" alt="" /></figure><p>Голосование по пятому раунду продлится до 18 декабря 2022 года. Опросы будут закрыты в 11:00 по МСК.</p>]]></content:encoded>
    </item>
    <item>
      <title>Второй раунд битвы языков программирования в 2022 году</title>
      <link>https://tproger.ru/articles/vtoroj-raund-bitvy-jazykov-programmirovanija-v-2022-godu</link>
      <comments>https://tproger.ru/articles/vtoroj-raund-bitvy-jazykov-programmirovanija-v-2022-godu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Рафаил Агазода]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/vtoroj-raund-bitvy-jazykov-programmirovanija-v-2022-godu</guid>
      <description><![CDATA[<p>Начинается второй этап битвы за звание лучшего языка программирования в 2022 году. Теперь выбрать придётся между Go и Python, Assembler и C.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/vtoroj-raund-bitvy-jazykov-programmirovanija-v-2022-godu">Второй раунд битвы языков программирования в 2022 году</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Язык ассемблера]]></category>
      <category><![CDATA[Лучший язык 2022]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 14 Dec 2022 08:00:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Завершился первый этап голосования за лучший язык программирования в 2022 году. Pascal уверенно обошёл Visual Basic и прошёл в следующий тур, а C# выиграл у С++ при отрыве всего в 50 голосов.</p><p>Результаты можно посмотреть <a href="https://tproger.ru/articles/nachalsja-battl-jazykov-programmirovanija-2022/">здесь</a>. Подпишитесь на тэг <a href="https://tproger.ru/tag/luchshij-jazyk-2022/">Лучший язык 2022</a> и следите за новыми раундами в личной ленте.</p><p>Сегодня в схватке столкнутся:</p><ul><li>Go и Python;</li><li>Assembler и C.</li></ul><figure><img src="https://media.tproger.ru/uploads/2022/12/battle_table-1.png" alt="" /></figure><p>Голосование по этим языкам программирования продлится до 15 декабря 2022 года. Опросы будут закрыты в 11:00 по МСК.</p>]]></content:encoded>
    </item>
    <item>
      <title>Стартует батл языков программирования 2022</title>
      <link>https://tproger.ru/articles/startuet-batl-jazykov-programmirovanija-2022</link>
      <comments>https://tproger.ru/articles/startuet-batl-jazykov-programmirovanija-2022?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Александровна]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/startuet-batl-jazykov-programmirovanija-2022</guid>
      <description><![CDATA[<p>Батл на звание лучшего языка программирования 2022 уже не за горами. Давайте узнаем, какой ЯП наиболее популярен по версии Tproger!</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/startuet-batl-jazykov-programmirovanija-2022">Стартует батл языков программирования 2022</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[Swift]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[BASIC]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Kotlin]]></category>
      <category><![CDATA[Язык ассемблера]]></category>
      <category><![CDATA[Pascal]]></category>
      <category><![CDATA[Лучший язык 2022]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 12 Dec 2022 08:00:40 GMT</pubDate>
      <content:encoded><![CDATA[<p>Предлагаем отвлечься от серьёзных рейтингов вроде <a href="https://tproger.ru/articles/luchshij-jazyk-programmirovanija-rejting-tiobe-2022/">TIOBE</a> или PYPL и выбрать лучший язык программирования 2022 по версии пользователей Tproger.</p><p>Правила батла по-прежнему просты:</p><ol><li>В батле участвует 16 языков программирования.</li><li>Ежедневно соревнуются две пары.</li><li>За любимый язык можно проголосовать в течение 24 часов.</li><li>Пары составляются рандомно, так что выбирайте язык, который субъективно нравится больше.</li><li>В финале мы определим тройку победителей.</li><li>Старт — 13 декабря, финал — 20 декабря.</li></ol><p>Примечание Забирайте эту запись в закладки, ведь именно в неё будут добавляться ссылки на последующие этапы голосования.</p><ul><li><a href="https://tproger.ru/articles/nachalsja-battl-jazykov-programmirovanija-2022/">Этап 1</a></li><li><a href="https://tproger.ru/articles/vtoroj-raund-bitvy-jazykov-programmirovanija-v-2022-godu/">Этап 2</a></li><li><a href="https://tproger.ru/articles/tretij-raund-bitvy-jazykov-programmirovanija-v-2022-godu/">Этап 3</a></li><li><a href="https://tproger.ru/articles/chetvjortyj-raund-bitvy-jazykov-programmirovanija-2022/">Этап 4</a></li><li><a href="https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2022/">Этап 5</a></li><li><a href="https://tproger.ru/articles/shestoj-raund-bitvy-jazykov-programmirovanija-2022/">Этап 6</a></li><li><a href="https://tproger.ru/articles/polufinal-bitvy-jazykov-programmirovanija-2022">Полуфинал</a></li><li><a href="https://tproger.ru/articles/final-bitvy-jazykov-programmirovanija-2022/">Финал</a></li><li><a href="https://tproger.ru/articles/battl-jazykov-programmirovanija-2022-zavershilsja-2/">Результаты</a></li></ul><p>Турнирная таблица:</p><figure><img src="https://media.tproger.ru/uploads/2022/12/Turnirnaja-tablica.png" alt="" /></figure><p>Старт уже завтра — 13 декабря в 11:00 МСК. Следите, участвуйте, голосуйте!</p>]]></content:encoded>
    </item>
    <item>
      <title>Пятый раунд битвы языков программирования 2021</title>
      <link>https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2021</link>
      <comments>https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2021?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Александровна]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2021</guid>
      <description><![CDATA[<p>Пятый раунд на звание лучшего языка программирования 2021 открывают следующие языки: C vs. Java, TypeScript vs. Go.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/pjatyj-raund-bitvy-jazykov-programmirovanija-2021">Пятый раунд битвы языков программирования 2021</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Лучший язык 2021]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 18 Dec 2021 08:00:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>Завершился четвёртый раунд батла, и к званию лучшего языка программирования приблизились C++, который одолел JavaScript, а также Kotlin, что обошёл Ruby почти на 500 голосов. Результаты можно посмотреть в <a href="https://tproger.ru/articles/chetvjortyj-raund-bitvy-jazykov-programmirovanija-2021/">соответствующем посте</a>.</p><p>Конкуренция становится всё жёстче, и в пятом раунде столкнутся:</p><ul><li>C vs. Java</li><li>TypeScript vs. Go</li></ul><figure><img src="https://media.tproger.ru/uploads/2021/12/Frame-13-2-1.png" alt="" /></figure><p>Выбирайте язык, который вам по душе. Голосование в пятом раунде завершится 19 декабря 2021 года в 11:00 по Москве.</p>]]></content:encoded>
    </item>
    <item>
      <title>Начался баттл языков программирования 2021</title>
      <link>https://tproger.ru/articles/nachalsja-battl-jazykov-programmirovanija-2021</link>
      <comments>https://tproger.ru/articles/nachalsja-battl-jazykov-programmirovanija-2021?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Александровна]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/nachalsja-battl-jazykov-programmirovanija-2021</guid>
      <description><![CDATA[<p>Выбираем лучший язык программирования 2021 из представленных пар. За звание лучшего сражаются: C vs. PHP, TypeScript vs. Assembler.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/nachalsja-battl-jazykov-programmirovanija-2021">Начался баттл языков программирования 2021</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Язык ассемблера]]></category>
      <category><![CDATA[Лучший язык 2021]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 14 Dec 2021 08:00:07 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сегодня за звание лучшего языка программирования 2021 по версии Tproger сражаются следующие пары:</p><ul><li>C vs. PHP</li><li>TypeScript vs. Assembler</li></ul><figure><img src="https://media.tproger.ru/uploads/2021/12/frame_13__5_.png" alt="" /></figure><p>Выбирайте любимый язык, исходя из личных симпатий. Голосование завершится 15 декабря 2021 года в 11:00 по Москве.</p><p>Ознакомиться с анонсом можно <a href="https://tproger.ru/articles/battl-jazykov-programmirovanija-2021-startuet-uzhe-zavtra/">здесь</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Баттл языков программирования 2021 стартует уже завтра</title>
      <link>https://tproger.ru/articles/battl-jazykov-programmirovanija-2021-startuet-uzhe-zavtra</link>
      <comments>https://tproger.ru/articles/battl-jazykov-programmirovanija-2021-startuet-uzhe-zavtra?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Александровна]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/battl-jazykov-programmirovanija-2021-startuet-uzhe-zavtra</guid>
      <description><![CDATA[<p>Отбросьте результаты исследований TIOBE, ведь в нашем баттле именно вы выбираете лучший язык программирования 2021.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/battl-jazykov-programmirovanija-2021-startuet-uzhe-zavtra">Баттл языков программирования 2021 стартует уже завтра</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[Swift]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[BASIC]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Kotlin]]></category>
      <category><![CDATA[Язык ассемблера]]></category>
      <category><![CDATA[Pascal]]></category>
      <category><![CDATA[Лучший язык 2021]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 13 Dec 2021 08:12:38 GMT</pubDate>
      <content:encoded><![CDATA[<p>Лучший язык программирования в 2021 году — это Java или Python? Совсем недавно рейтинг TIOBE взбудоражил всё IT-сообщество, ведь именно Python потеснил извечных лидеров в виде Java и C.</p><p>Но давайте отвлечёмся от официальной статистики и узнаем, какие языки предпочитаете именно вы! Завтра стартует баттл языков программирования 2021. Правила просты:</p><ol><li>Всего участвует 16 языков программирования.</li><li>Каждый день соревнуются две пары.</li><li>На возможность проголосовать за любимый язык отводится 24 часа.</li><li>Пары составляются рандомно.</li><li>Выбирайте тот язык, который субъективно нравится вам больше.</li><li>В финале мы определим победителей — языки которые заняли первое, второе и третье место.</li><li>Старт — 14 декабря, финал — 21 декабря.</li></ol><p>Так выглядит изначальная турнирная таблица:</p><figure><img src="https://media.tproger.ru/uploads/2021/12/languages_battle_2021_announce.png" alt="" /></figure><p>А вот как мы <a href="https://tproger.ru/tag/toplang2020/">выбирали лучший язык программирования</a> в прошлом году.</p><p>Подписывайтесь на уведомления на сайте, чтобы быть в курсе лидеров и новых голосований.</p><p>Результаты баттла можно посмотреть по <a href="https://tproger.ru/articles/battl-jazykov-programmirovanija-2021-zavershilsja/">ссылке</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Необычная история становления программиста: от первых троянов до собственной программы для шифрования файлов</title>
      <link>https://tproger.ru/articles/neobychnaja-istorija-stanovlenija-programmista-ot-pervyh-trojanov-do-sobstvennoj-programmy-dlja-shifrovanija-fajlov</link>
      <comments>https://tproger.ru/articles/neobychnaja-istorija-stanovlenija-programmista-ot-pervyh-trojanov-do-sobstvennoj-programmy-dlja-shifrovanija-fajlov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Игорь Соловьев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/neobychnaja-istorija-stanovlenija-programmista-ot-pervyh-trojanov-do-sobstvennoj-programmy-dlja-shifrovanija-fajlov</guid>
      <description><![CDATA[<p>Рассказ разработчика о пути в IT — о разочарованиях, просветлениях и внутреннем пожаре, который вёл от ранних экспериментов к собственным программам.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/neobychnaja-istorija-stanovlenija-programmista-ot-pervyh-trojanov-do-sobstvennoj-programmy-dlja-shifrovanija-fajlov">Необычная история становления программиста: от первых троянов до собственной программы для шифрования файлов</a>»</p>]]></description>
      <category><![CDATA[Обучение программированию]]></category>
      <category><![CDATA[Криптография]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Пост пользователя]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 20 Apr 2021 10:08:54 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет, читатель. Возможно, ты уже опытный разработчик и способен обучать других людей программированию. Может быть, ты новичок, только собираешься начать свой путь в IT и не знаешь, с чего начать (да не удержат тебя семеро). Может быть, ты системный программист и пишешь серьёзные программы для государственных предприятий военно-промышленного комплекса. Может быть, ты студентка филологического факультета местного ВУЗа и развлекаешь себя программированием простых программ на Python или JavaScript.</p><p>Но это неважно. Важен пожар внутри тебя. Я бы хотел рассказать тебе историю моего необычного развития в IT, и то, куда меня ведёт пожар, горящий внутри меня. Я бы хотел рассказать тебе, на какие грабли я наступал, какие инструменты выбирал и какие уроки выучил на этом необычном и трудном пути.</p><p>Программирование для меня — просто хобби, которое я считаю одной из главных частей своей жизни. Сейчас я разрабатываю как для себя, так и для других, крошечную свободную программу для шифрования файлов, которой пользуюсь сам просто от того, что меня не устраивают все остальные.</p><h2>Первые трояны</h2><p>Первый компьютер мне купили в 2007 году, когда я учился в 8 классе. Я обожаю компьютерные игры и сейчас в них тоже играю. Первыми же моими играми были Painkiller и S.T.A.L.K.E.R. Но ещё мне было интересно, как работает компьютер, что он может и чего не может.</p><p>Я мог бы начать изучение операционных систем и языка программирования Pascal, как все нормальные школьники, но меня слишком вдохновляли истории взломов, совершенных такими звездами компьютерного андеграунда, как Кевин Митник, Адриан Ламо, Джонатан Джеймс и т.д. В их руках я видел почти безграничную, свирепую, непобедимую власть, которую они обрели лишь терпением, желанием и опытом. Я считал их полубогами и хотел быть подобным им. Я был восхищен тем, как простые люди могут нажать пару клавиш и обрушить что-нибудь, да так, что мир вздрогнет.</p><p>В один из дней моей юности я открыл Internet Explorer, зашёл на Яндекс и ввел самый глупый запрос: «как создать вирус».</p><p>В интернете того времени была масса инструкций, следуя которым можно было создать почти всё, начиная от троянов и заканчивая бестелесными полиморфными сетевыми червями, вроде Code Red или SQL Slammer. После прочтения массы сомнительных и околокриминальных источников с подозрительной рекламой эротического и мошеннического содержания я решил начать с написания .bat троянов, потому что это было легче всего.</p><p>Интерпретатор командной строки Windows XP, которой я тогда пользовался, позволял считывать команды прямо из файлов с расширением .bat. Я написал несколько троянов, один из которых прописывал себя в автозагрузку операционной системы и постоянно перезагружал компьютер. Я казался себе гуру, суперхакером, чуть ли не вершителем судеб, и тот огонь, вспыхнувший во мне от понимания того, на что я способен, не погас до сих пор. Я понял, что создание программы для компьютера — это не спорт, где нужны годы тренировок, и не искусство, требующее вдохновения и многолетнего опыта.</p><p>Если архитектор везде натыкается на материальные преграды вроде стоимости строительных материалов, то создатель программ — только на ограниченность своего ума, не считая стоимости компьютера. Смог я — сможет любой. Предела нет.</p><p>Позже я узнал про языки программирования, какими они бывают и зачем используются. Я узнал, что существует целый зоопарк операционных систем, и Windows XP — только одна из них. Я прочитал, что такое троян, червь, вирус, исходный код, дизассемблер, firewall, эксплойт, ФСБ, обыск и т.д. Со временем что-то во мне изменилось и я задумался, а смогу ли я создать что-нибудь по-настоящему полезное. Скачав первую попавшуюся пиратскую версию среды быстрой разработки приложений Delphi 7, о которой я узнал на одном из тех нехороших сайтов, я начал пробовать писать программы.</p><h2>Первая программа</h2><p>Первой разработанной мной программой была, насколько я помню, консольная программа для шифрования файла по паролю. Она открывала файл на чтение/запись, из которого читались данные, ксорились с паролем и записывались обратно в файл. Программа была написана так, что её исходный код лучше не видеть никому и никогда, чтобы просто не стать седым. Вот пример кода, который там реально был:</p><p>Уже и не помню, сколько файлов я испортил, пытаясь довести программу до ума. В итоге xor (сложение по модулю два) был выброшен на свалку, а выбран был алгоритм шифрования DES. Но со временем программа стала настолько сложной, что я уже сам не мог сказать, что и как в ней работает. И это в моей программе! Но меня ожидал хороший итог.</p><p>Хороший, потому что я понял свою ошибку — я не прочитал, как не надо делать, потому что это просто не пришло в голову. Мне даже не было дела до того, что до меня такие идиотские ошибки уже делали тысячи и тысячи людей! Я был невероятно некомпетентен!</p><p>Излазив сотни сайтов, я узнал про алгоритмы шифрования, какими они бывают, что такое режим шифрования и чем собственно плохи алгоритм DES и режим ECB (режим электронной кодовой книги), что такое перебор пароля, перебор ключа, криптоанализ, USA NSA и т.д. Но информации всё равно было мало, и мало настолько, что я был зол.</p><p>Как это так? В мире полно криптографических программ, а как их правильно разрабатывать, на форумах никто не знает? Да не может такого быть, думал я. Как оказалось, ещё как может.</p><h2>Первый взлом программы</h2><p>Первой книгой по информационной безопасности, которую я прочёл, была пиратская версия книги Криса Касперски «<i>Техника и философия хакерских атак</i>». Я не просто её прочел, я её «проглотил». Найдя для себя хорошего кумира, я стал читать его книги и статьи. Я прочел «<i>Записки исследователя компьютерных вирусов</i>», «<i>Компьютерные вирусы изнутри и снаружи</i>», статьи вроде «<i>Какие следы ты оставил после себя</i>» и т.д.</p><p>Я начал понемногу учить язык ассемблера для процессора x86, с которым познакомился благодаря отладчику уровня пользователя OllyDbg и дизассемблеру IDA Pro, который использовал в своей книге Крис. Всё, разумеется, было пиратским: и Windows XP, и IDA Pro, и всё остальное. Мне было неловко от того, что другие умеют делать из лицензионных программ пиратские, а я не умею. Я думал, что Кевин Митник уж точно знает, как взламывать программы, и захотел уметь так же.</p><p>Первый crackme (программа, созданная специально, чтобы быть взломанной) я взломал где-то за один час. Потом я взломал ещё один crackme, и ещё один, и ещё. Так я дошёл до того, что теперь мог редактировать собственноручно разработанные программы, к чему успешно перешёл. С помощью пиратской версии программы WinHex я редактировал свои программы и смотрел, что будет. Я менял значения констант, команду ADD (сложение) на команду SUB (вычитание), превращал циклы с условием в бесконечные циклы, а условные переходы JE (перейти, если равенство) в безусловные JMP.</p><p>Когда я перешёл от взломов к программированию на языке ассемблера, я написал программу, которая меняла команду ADD на SUB прямо во время исполнения, а позже процессор выполнял изменённые команды. Я понял, что теперь могу написать любую программу. Чтобы узнать, что делает такая программа, её было мало прочитать, её нужно было именно запустить. Так я открыл для себя трассировку программ (выполнение программы по одной команде).</p><p>Это было волшебно! Я могу, и могу такое! Ай да я, ай да мамин суперхакер, думал я.</p><p>Позже, поверив в себя, расправив плечи и надев чёрные очки, я начал творить то, что могло стоить мне свободы. Я решил перейти на сетевой уровень IT, но используя для этого не учебники информатики, а статьи и книги того же Криса Касперски. Я узнал, что существуют протоколы связи программ друг с другом, такие как HTTP, FTP, SMTP, POP3, как взламывают компьютеры по сети, что такое переполнение буфера в стеке с перезаписью адреса возврата, что такое «куча», DDoS атака и т.д.</p><p>На всё тех же сомнительных сайтах с нехорошей рекламой я многое прочёл про сетевые взломы, эксплойты, программы для перебора паролей, уязвимости и т.д. Я думал, что вот-вот взломаю весь мир и поставлю на колени плачущего директора ЦРУ. Я думал.</p><p>В процессе прочтения и попутного обучения огонёк во мне снова вспыхнул. Я снова пошёл по темной дорожке старых, восхищавших меня в самом начале пути полузаконных людей. В ночь с субботы на воскресенье, когда я пытался подобрать пароль к одному из FTP-серверов с помощью скачанной из интернета программы для перебора паролей, даже не зная, в какой стране находится сервер и зачем мне вообще к нему доступ, на домашний телефон позвонил неизвестный. Голос в трубке, искажённый ужасными помехами, спросил:</p><p><i>— Здравствуйте, вы дома пользуетесь интернетом?</i></p><p><i>— Ээээ… Да. А вы от какого-то провайдера звоните? </i>— спросил я, и посмотрел на настенные часы, которые показывали 04:30 утра.</p><p><i>— Ээээ… Нет,</i> — ответил голос в трубке и мы оба замолчали. Я первый раз в жизни услышал то, что теперь зову «ехидным молчанием», которое ужасно меня напугало! Мне показалось, что бетонные стены квартиры начали сжимать меня! Вдруг я понял, что рекламировать свои услуги ни один провайдер в выходной день, тем более в половине пятого утра, не будет. После ехидного молчания со стороны собеседника я повесил трубку. Спустя два часа я уже ехал в деревню к бабушке на первой же электричке, пытаясь предугадать, какой же срок мне грозит.</p><p>Всё обошлось, но такого опыта я не пожелаю и врагу. Я понял, что есть люди гораздо умнее меня и отрезвлять умы они умеют ещё как. Простым звонком в четыре утра. И да, я не хочу знать, кто мне звонил.</p><h2>Разработка собственных программ</h2><p>Будучи испуганным, отрезвлённым и просветлённым, я быстро свернул обратно на светлую дорожку, начав думать, чего же мне ещё надо.</p><p><i>— Что я могу? О, точно. Мне нужна своя база данных, как в фильме про агентов ЦРУ.</i></p><figure><img src="https://media.tproger.ru/uploads/2021/04/IMAGE_3.png" alt="" /></figure><p>Сказано – сделано.</p><p>Я написал её где-то за неделю, и да, я знаю, дизайнер из меня так себе. Программе нужно было название, данное в какой-нибудь крутой корпорации, и я придумал её — Plexus. Это не база данных, а система управления базой данных (СУБД), работающая с файлами Microsoft Access, поддерживающая шифрование AES-KSM-256, хеширование MD5 и SHA-1, смену пароля пользователя перешифрованием ключа шифрования записей в базе данных, смену изображения, уничтожение данных на диске и поиск по маске.</p><p>Режим шифрования KSM я придумал сам: это тот же самый режим ECB, в котором в качестве ключа шифрования следующего блока данных используется hash (контрольная сумма) ключа шифрования предыдущего блока. Программа устанавливалась на компьютер простым копированием файлов из архива, а мне хотелось чего-то настоящего, ТруЪ, и я написал для неё установщик. Позже, когда всё было готово, я вспомнил, что забыл записать «лицензионный» ключ для единственного установщика моей же программы, что заставило меня написать keygen.</p><figure><img src="https://media.tproger.ru/uploads/2021/04/IMAGE_6.png" alt="" /></figure><p>Да, я написал генератор «лицензионных» ключей для собственной программы! А откуда, вы думали, разработчики программ берут лицензионные ключи, которые потом продают за 1500 рублей? У них есть свой keygen, а у меня его не было.</p><p>Я снова ощутил себя вершителем судеб, пока не нашёл на форумах информацию о том, что такие программы пишут студенты 3-4 курса технических ВУЗов.</p><p>Что? Студенты? Я не какой-то там студент! Я Криса Касперски читал!</p><p>Мне было мало, и я горел страстью! Мне нужно было творить, писать, создавать! Только ООН могла мне помешать вытворять то, что я хочу. И я написал в среде Delphi 7 целую базу данных различных программ. Например, программу для «склеивания» файлов, которую я написал, пытаясь создать собственный WinRar, что, кстати, не получилось. Пародия на Bourne Shell, за которую мне ужасно стыдно до сих пор.</p><figure><img src="https://media.tproger.ru/uploads/2021/04/IMAGE_2.png" alt="" /><figcaption>Программа для склеивания файлов</figcaption></figure><p>Программа для вычисления контрольных сумм как файлов, так и текстов, была написана за один присест, трояны-шифровальщики (на самом деле, серьёзные вайперы), программы для создания больших изображений путем «склеивания» массы маленьких, патчеры бинарных файлов, файловые шредеры и даже простой чат с клиент-серверной архитектурой, поддержкой шифрования сообщений и поддержкой ника (сетевого имени). Ещё я написал аналог программы «Поиск» для Windows XP, но это уже в прошлом.</p><figure><img src="https://media.tproger.ru/uploads/2021/04/IMAGE_4.png" alt="" /><figcaption>Патчер бинарных файлов</figcaption></figure><figure><img src="https://media.tproger.ru/uploads/2021/04/IMAGE_5.png" alt="" /><figcaption>Аналог поиска для Windows XP</figcaption></figure><p>В конце концов, я изрядно устал. Мне казалось, что я написал вообще всё, что можно было написать. Мне стало скучно. Мне казалось, что писать программы — это несерьёзно. Я правда так думал!</p><h2>Переход на язык Си и создание программы для шифрования файлов</h2><p>Я задумался, смогу ли я написать ядро операционной системы, интернет-браузер, полиморфного многовекторного червя с функционалом анонимного удалённого управления, сайт вроде “ВКонтакте”? Ответ был: нет. И я обратил внимание на язык программирования, как мне казалось, более серьёзный, сильный, взрослый, круче, чем языки Object Pascal и Delphi. Это был язык Си.</p><p>Так я начал карабкаться на ступень, на которой уверенно стоят не просто школьники, перебирающие пароли к чужим серверам, а настоящие титаны инженерной мысли мира IT вроде Эрика Реймонда, Ричарда Столлмана и Линуса Торвальдса. Как оказалось, то, что я делал раньше, скорее всего, делали и они. Но сейчас для них это просто мелочь, недостойная внимания.</p><p>Писать программы можно научиться за короткое время, но нельзя за короткое время научиться думать точно.</p><p>Я даже не знал, что это такое — думать точно. Я даже не думал! Я просто делал и всё. Как карта ляжет. Изучение языка Си открыло мне глаза на настоящее программирование. Я поставил GNU/Linux Debian рядом с уже сотни раз переустановленной Windows XP, установил gcc, cppcheck, Kate и начал постигать самую серьёзную, на мой взгляд, ступень программирования.</p><p>Я узнал, что такое динамическое выделение памяти, как устроены языки программирования и чем они отличаются, что такое типизация, указатели и их арифметика, как компилятор превращает исходные тексты в ассемблерный лист и позже собирает из него бинарный файл.</p><p>Я понял, почему я устал, почему исписался. Мне не хватало настоящего хардкора, если хотите, Мужъского ТруЪ. Я понял, что в течение нескольких лет я занимался учебными стрельбами, а не реальными баталиями.</p><p>Я решил вернуться к своей первой задумке, а именно программе для шифрования файлов. К тому времени я уже перепробовал массу программ для шифрования файлов и удовлетворить мои потребности смогла только GnuPG. Но зачем так сложно? Делать нужно просто, будто для дураков. Первое, что я сделал, это поставил задачу.</p><p><i>Нужно зашифровать файл так, чтобы никто, даже директор ЦРУ, никогда не получил открытый текст, не зная пароля или не имея доступа к ключевому файлу. Пароль же перебрать нельзя, а если и можно, то ждать придётся неисчислимое количество времени. Взлом шифротекста методами криптоанализа должен быть невозможен в принципе.</i></p><p>Задача казалась непосильной, но позже стала тривиальной. Я более или менее изучил язык Си и начал писать ту самую неповторимую программу, которую писал когда-то. Я сразу понял, увидел, что должно получиться.</p><p>Меня как будто осенило — старая версия программы была просто не моего уровня.</p><p>Я вдруг чётко стал видеть путь и инструменты, которые нужно использовать, чтобы получить максимум, приложив минимум усилий. Но заразился страшной болезнью, которой страдают все программисты, переходя на новый, продвинутый уровень: Сишностью.</p><p>Я больше не могу видеть свой старый код. Меня от него трясет и корёжит. Правда. Я считаю, что следующий код хорош, но любой другой просто шлак, даже мой, что заставляет меня писать аккуратно, как будто я программирую ракету для миссии на Нептун! Что со мной? Все нормально. Просто, я расту над собой. Если ты новичок, тебя ждёт то же самое. Всех ждёт!</p><p>Первой прочитанной научной книгой стала пиратская версия книги Брюса Шнайера «<i>Прикладная криптография</i>», которую «проглотить» оказалось не так просто. Она оказалась мне не по зубам, и начался тяжёлый подъем в гору просветления.</p><p>«Криптография бывает двух типов: криптография, которая помешает читать ваши файлы вашей младшей сестре, и криптография, которая помешает читать ваши файлы людям из правительства».<br />«Прикладная криптография», Брюс Шнайер.</p><p>Я медленно, но верно изучил алгоритмы шифрования, выбрав пять наиболее понравившихся мне, а позже выбрав шестой, Twofish, режимы шифрования, выбрав в итоге CFB (режим обратной связи по шифротексту), за что спасибо учёным, авторам <a href="http://www.apmi.bsu.by/blog/cryptology/cbc-vs-cfb.html">статьи на сайте одного белорусского ВУЗа</a>. Я выбрал всё лучшее на тот момент, но не прочитал главного — как делать не надо. Снова.</p><p>Как оказалось, защита информации — это целая наука, и я думаю, что успешно поднимаюсь на эту ступень, хоть и маленькими шажками. Следующей книгой Шнайера, изученной мной, стала пиратская версия книги «<i>Секреты и ложь: безопасность данных в цифровом мире</i>».</p><p>После её прочтения я понял: безопасность — это процесс, а не инструмент. Дело не в винтовке, дело в профессионализме стрелка. Я понял. Я — плохой стрелок. Это и было ключом ко всему — познать границы своей компетентности и, увидев пятна незнания, взять их штурмом желания, терпения и опыта. Одно пятно за другим.</p><p>Сейчас разрабатываемую и поддерживаемую мной программу я использую сам для шифрования файлов размером до 2 ГБ включительно. Мне больше и не надо. Программа свободна и использовать ее может кто угодно и для чего угодно.</p><p>Пароль, из которого генерируются ключи шифрования, действительно не перебрать на компьютерах не то что сегодняшнего дня (2021 года), а, скорее всего, вообще никогда. Криптоанализ шифротекстов, насколько я могу судить, неэффективен.</p><p>Единственный шанс получить открытый текст из шифротекста без знания пароля — это украсть открытый текст до шифрования. Как и у WinRar, копию которого я когда-то безуспешно пытался написать. Размер самой программы, точнее, её консольной версии, около 90 КБ, графической версии — около 480 КБ.</p><figure><img src="https://media.tproger.ru/uploads/2021/04/IMAGE_7.png" alt="" /><figcaption>Консольная версия программы</figcaption></figure><figure><img src="https://media.tproger.ru/uploads/2021/04/IMAGE_8.png" alt="" /><figcaption>Графическая версия программы</figcaption></figure><p>Такие малютки, но столько мощи! Сегодня такие программы уже не пишут. Ну разве что ребята из проекта GNU. Я действительно горжусь тем, что создал, пройдя по-настоящему тяжёлый и долгий путь. Мне ещё многому предстоит научиться, многое сделать, но я чётко вижу, куда идти и что нужно делать, а, главное, знаю, как не надо делать.</p><p>Я сделал это. Сделаешь и ты. Главное, подогревать в себе огонь тем, что по-настоящему разжигает страсть!</p>]]></content:encoded>
    </item>
    <item>
      <title>Нейросеть научили подражать программному коду, написанному на С и С++</title>
      <link>https://tproger.ru/news/nejroset-nauchili-podrazhat-programmnomu-kodu-napisannomu-na-s-i-s</link>
      <comments>https://tproger.ru/news/nejroset-nauchili-podrazhat-programmnomu-kodu-napisannomu-na-s-i-s?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/nejroset-nauchili-podrazhat-programmnomu-kodu-napisannomu-na-s-i-s</guid>
      <description><![CDATA[<p>Проект MESS Lab DoesNotExist.codes предлагает угадать автора фрагмента: модель GPT2 774M обучили на 10 000 популярных пакетов Debian.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/nejroset-nauchili-podrazhat-programmnomu-kodu-napisannomu-na-s-i-s">Нейросеть научили подражать программному коду, написанному на С и С++</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 24 Feb 2021 14:47:45 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчики из MESS Lab представили интересный проект — <a href="https://doesnotexist.codes/">DoesNotExist.codes</a>. Посетителям одноимённого сайта предлагается угадать, кто именно написал демонстрируемый код: человек или нейросеть.</p><p>Выглядит игра следующим образом: пользователям показывается кусок кода на С/С++, после чего им необходимо выбрать, кто написал его. В верхней части сайта есть две кнопки для этого: Real («Реальный человек») и GPT2 (нейросеть). Там же после первого выбора будет показан счёт с количеством верных и неправильных ответов.</p><figure><img src="https://media.tproger.ru/uploads/2021/02/Screen-Shot-2021-02-24-at-17.44.44.png" alt="" /><figcaption>«Интерфейс» DoesNotExist.codes</figcaption></figure><p>К слову, именно модель GPT2 774M и легла в основу всего проекта. Её тренировали на 10 000 самых популярных пакетах Debian, написанных на С/С++. При этом «реальные куски кода» для DoesNotExist.codes также были взяты из этих пакетов.</p><p>Источник: <a href="https://doesnotexist.codes/">DoesNotExist.codes</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Где общаются разработчики: русскоязычные чаты программистов</title>
      <link>https://tproger.ru/digest/gde-obshhajutsja-razrabotchiki-russkojazychnye-chaty-programmistov</link>
      <comments>https://tproger.ru/digest/gde-obshhajutsja-razrabotchiki-russkojazychnye-chaty-programmistov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Борисенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/digest/gde-obshhajutsja-razrabotchiki-russkojazychnye-chaty-programmistov</guid>
      <description><![CDATA[<p>Подборка сообществ в Slack и Telegram, где можно задать вопрос по JavaScript, фронтенду, Python, PHP и другим технологиям и получить ответ.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/digest/gde-obshhajutsja-razrabotchiki-russkojazychnye-chaty-programmistov">Где общаются разработчики: русскоязычные чаты программистов</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Data Science]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Подборки]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 27 Jan 2021 08:30:25 GMT</pubDate>
      <content:encoded><![CDATA[<p>Нашли для вас несколько чатов программистов, в которых можно задать вопрос и получить ответ. Перед тем как что-то спросить, всегда стоит прочитать правила конкретного сообщества и воспользоваться поиском.</p><h2>Чаты программистов по технологиям</h2><h3>JavaScript</h3><p><a href="https://allthatjs.herokuapp.com/">Slack Workspace</a> для обсуждения всего, что связано с JavaScript. При выборе интересующих вас тем, во время регистрации, нажимайте на сами темы, а не на чекбоксы. В чате состоит более 700 участников.</p><p><a href="https://t.me/JS_learn">Сообщество</a> JS программистов в Telegram. Больше тысячи участников.</p><h3>Frontend</h3><p>Slack Workspace посвящённый вебу и всему что с ним связано. Имеет более пяти тысяч участников. Сейчас больше активности в их <a href="https://t.me/webstandards_chat">Telegram-чате</a>.</p><p><a href="http://slack.spb-frontend.ru/">Slack Workspace</a>  <a href="https://tproger.ru/articles/frontend-roadmap-2021/">фронтэндеров</a> из Санкт-Петербурга. Сообщество устраивает оффлайн встречи. Сейчас насчитывает более 1700 участников.</p><h3>Python</h3><p><a href="https://slack.python.ru/">Slack Workspace</a> сайта Python.ru. В нём состоит более трёх тысяч человек. Можно задать вопросы по Python, Flask, Django и другим технологиям. В чате организуют оффлайн встречи программистов.</p><h3>PHP</h3><p><a href="https://t.me/phpGeeksJunior">Группа в Telegram</a> для программистов новичков в PHP. Почти две тысячи участников.</p><h3>iOS</h3><p><a href="https://cocoadevelopers.club/">Slack Workspace</a> где можно обсудить Swift, Objective-C, Cocoa, машинное обучение, реактивное программирование и множество других тем. Сейчас в чате более трёх тысяч участников.</p><h3>Android</h3><p><a href="https://github.com/rus-speaking/Russian-speaking-Android-developers-community">Gitter сообщества</a> android разработчиков. Есть отдельный чат для программистов, использующих Xamarin-технологии.</p><h2>Java\Kotlin</h2><p><a href="https://t.me/springframeworkio">Группа</a> в Telegram обо всём что связано с Java и Kotlin. Полторы тысячи участников.</p><h3>Data Science</h3><p><a href="https://ods.ai/">Сообщество</a> Open Data Science с сотнями каналов на различные темы, связанные с наукой о данных, машинным обучением и ИИ.</p><h2>Go</h2><p><a href="https://t.me/gogolang">Сообщество</a> Gо программистов в Telegram. Более четырёх тысяч участников.</p><h3>GameDev</h3><p><a href="http://hgam-invite.herokuapp.com/">Slack Workspace</a> обо всём что связано с разработкой игр. Можно обсудить геймдизайн, GFX, iOS, Android, Unity, Unreal Engine и многое другое. Более двух тысяч участников.</p><h3>С++</h3><p><a href="https://t.me/supapro">Группа в Telegram</a> для новичков в С++. Можно задавать простые вопросы о языке и IDE. Более трёх тысяч участников.</p><p><a href="https://t.me/ProCxx">Группа в Telegram</a> для более сложных вопросов по C\C++. Более четырёх тысяч участников.</p><h2>Программирование</h2><p>В Slack-чате курсов по программированию Хекслет можно обсудить всё, что связано с разработкой. <a href="https://slack-ru.hexlet.io/">В нём</a> состоит более восемнадцати тысяч участников.</p><h2>Другие чаты программистов</h2><p>Помогите нам составить наиболее полный список русскоязычных чатов программистов. Делитесь ими в комментариях. Мы добавим их в подборку.</p>]]></content:encoded>
    </item>
    <item>
      <title>Четырёхлетний курс обучения Computer Science воссоздали при помощи 1079 видео с YouTube</title>
      <link>https://tproger.ru/news/chetyrjohletnij-kurs-obuchenija-computer-science-vossozdali-pri-pomoshhi-1-079-video-s-youtube</link>
      <comments>https://tproger.ru/news/chetyrjohletnij-kurs-obuchenija-computer-science-vossozdali-pri-pomoshhi-1-079-video-s-youtube?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/chetyrjohletnij-kurs-obuchenija-computer-science-vossozdali-pri-pomoshhi-1-079-video-s-youtube</guid>
      <description><![CDATA[<p>Авторы Laconic Machine Learning воссоздали программу американского университета: 40 курсов, 4 года по два семестра и 1079 обучающих роликов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/chetyrjohletnij-kurs-obuchenija-computer-science-vossozdali-pri-pomoshhi-1-079-video-s-youtube">Четырёхлетний курс обучения Computer Science воссоздали при помощи 1079 видео с YouTube</a>»</p>]]></description>
      <category><![CDATA[Математика и теория вероятностей]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Обучающие курсы]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 13 Jan 2021 08:22:52 GMT</pubDate>
      <content:encoded><![CDATA[<figure><img src="https://media.tproger.ru/uploads/2021/01/2-14.jpg" alt="" /></figure><p>На Laconic Machine Learning появился огромный <a href="https://laconicml.com/computer-science-curriculum-youtube-videos/">материал</a> на тему Computer Science. В нём авторы ресурса попытались воссоздать четырёхлетний курс обучения компьютерным наукам при помощи видео с YouTube. В общей сложности для этих целей было использовано 1079 обучающих видеоролика.</p><p>Материал разделён на сегменты, соответствующие учебному плану в типичном американском университете: 40 курсов, 4 академических года по 2 семестра в каждом.</p><p>На первом курсе предлагается изучить основы структурного программирования (при помощи языка Си), дискретную математику, математический анализ и т.д — в общем-то, те самые дисциплины, которые даются студентам первого курса в большинстве вузов даже нашей страны.</p><p>Стоит отметить, что в рамках предлагаемого плана обучения можно найти изучение машинного обучения, создание мобильных приложений под iOS и Android, робототехнику, компьютерное зрение и много чего ещё интересного.</p><p>Сами авторы материала отмечают, что их подборка хоть и является крайне полезной, всё же не заменит полноценного обучения в университете. Но при этом она может помочь разобраться в Computer Science как студентам, так и тем, кто так и не поступил в вуз.</p><p>Источник: <a href="https://laconicml.com/computer-science-curriculum-youtube-videos/">Laconic Machine Learning</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Разработчик объяснил, как работает распрыжка в Quake на уровне исходного кода</title>
      <link>https://tproger.ru/news/razrabotchik-objasnil-kak-rabotaet-raspryzhka-v-quake-na-urovne-ishodnogo-koda</link>
      <comments>https://tproger.ru/news/razrabotchik-objasnil-kak-rabotaet-raspryzhka-v-quake-na-urovne-ishodnogo-koda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/razrabotchik-objasnil-kak-rabotaet-raspryzhka-v-quake-na-urovne-ishodnogo-koda</guid>
      <description><![CDATA[<p>На канале Matt's Ramblings разобрали код оригинальной Quake: за скорость на земле и в воздухе отвечают две функции, на них держатся трюки.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/razrabotchik-objasnil-kak-rabotaet-raspryzhka-v-quake-na-urovne-ishodnogo-koda">Разработчик объяснил, как работает распрыжка в Quake на уровне исходного кода</a>»</p>]]></description>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 11 Jan 2021 07:28:36 GMT</pubDate>
      <content:encoded><![CDATA[<p>На YouTube-канале Matt’s Ramblings <a href="https://youtu.be/v3zT3Z5apaM">появилось</a> свежее видео с разбором исходного кода оригинальной Quake. В нём автор ролика рассказал о том, как работают самые известные «баги» игры, в том числе и легендарная распрыжка, на уровне исходного кода.</p><figure><img src="https://media.tproger.ru/uploads/2021/01/1-8.jpg" alt="" /></figure><p>Сама игра написана языке Си. Но для удобства большинства своих зрителей, в видео используется объяснение на примере псевдопитона.</p><p>В момент, когда игрок находится на земле, скорость его перемещения вычисляется при помощи функции:</p><p>Что же касательно вычисления скорости в момент нахождения в воздухе, то за это отвечает другая функция:</p><p>На основе этой базы строятся такие «фишки» серии Quake как распрыжка, wall running и зигзагинг. При этом, стоит отметить, что в дальнейшем все эти движения стали частью и других серий. Так, благодаря использованию одной из версий id Tech в качестве основы для <a href="https://en.wikipedia.org/wiki/GoldSrc">движка Half-Life</a>, чуть позже Counter-Strike также стала известна распрыжками.</p><p>Источник: <a href="https://youtu.be/v3zT3Z5apaM">Matt’s Ramblings</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Названы победители конкурса на самый запутанный код на языке Си</title>
      <link>https://tproger.ru/news/nazvany-pobediteli-konkursa-na-samyj-zaputannyj-kod-na-jazyke-si</link>
      <comments>https://tproger.ru/news/nazvany-pobediteli-konkursa-na-samyj-zaputannyj-kod-na-jazyke-si?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/nazvany-pobediteli-konkursa-na-samyj-zaputannyj-kod-na-jazyke-si</guid>
      <description><![CDATA[<p>На конкурсе IOCCC за 2020 год в четырёх из пятнадцати категорий победил разработчик из Новосибирска Илья Курдюков — среди работ есть вычисление MD5.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/nazvany-pobediteli-konkursa-na-samyj-zaputannyj-kod-na-jazyke-si">Названы победители конкурса на самый запутанный код на языке Си</a>»</p>]]></description>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 05 Jan 2021 09:00:51 GMT</pubDate>
      <content:encoded><![CDATA[<p>На сайте «Международного соревнования по запутанному Си-коду» (IOCCC) <a href="https://www.ioccc.org/2020/whowon.html">появились</a> имена победителей за 2020 год. В общей сложности было сформировано 15 категорий, в 4 из которых лидером оказался разработчик из Новосибирска <a href="https://github.com/ilyakurdyukov">Илья Курдюков</a>.</p><p>Одной из самых интересных работ отечественного программиста можно назвать <a href="https://www.ioccc.org/2020/kurdyukov1/index.html">инструмент вычисления хэшей MD5</a>. Его код оформлен в виде круга. Одной из главных сложностей при уменьшения размеров утилиты Курдюков назвал длину таблицы MD5. Она, с учётом констант, составляет 64 х 4 байта.</p><figure><img src="https://media.tproger.ru/uploads/2021/01/2.jpg" alt="" /></figure><p>Были и не менее интересные работы от других участников. Например, японский разработчик Юсуки Эндо написал приложение, которое выводило надпись «May the IOCCC be with you» анимированную в стиле начальных титров из Star Wars:</p><figure><img src="https://media.tproger.ru/uploads/2021/01/1.jpg" alt="" /></figure><p>Отметим, что главной задачей участников соревнования от IOCCC была разработка программы на языке Си, которая была бы максимально запутанной и нечитабельной. В то же время приложение должно было успешно собираться, решать какую-то задачу и весить не более 4 КБ.</p><p>Источник: <a href="https://www.ioccc.org/2020/index.html">IOCCC</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Как компилятор преобразует код на C в Assembler?</title>
      <link>https://tproger.ru/video/kak-kompiljator-preobrazuet-kod-na-c-v-assembler</link>
      <comments>https://tproger.ru/video/kak-kompiljator-preobrazuet-kod-na-c-v-assembler?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Борисенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/video/kak-kompiljator-preobrazuet-kod-na-c-v-assembler</guid>
      <description><![CDATA[<p>Автор видео с ручкой и бумагой сравнивает программу на C и её ассемблерный вид на примере вывода чисел Фибоначчи, объясняя машинный код.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/video/kak-kompiljator-preobrazuet-kod-na-c-v-assembler">Как компилятор преобразует код на C в Assembler?</a>»</p>]]></description>
      <category><![CDATA[Компиляторы]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Язык ассемблера]]></category>
      <category><![CDATA[Видео]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 03 Jan 2021 09:12:27 GMT</pubDate>
      <content:encoded><![CDATA[<p>Автор видео, используя только ручку и бумагу, сравнивает код на C и скомпилированный в Assembler. Он делает это на примере программы, которая выводит на экран <a href="https://tproger.ru/problems/finding-fibonacci/">числа Фибоначчи</a>.</p><p>В комментариях подсказывают, что в реальности машинный код получается более оптимизированным. <a href="https://godbolt.org/z/7dYv58">По этой ссылке</a> вы найдете компилятор из языка Си в Assembler, который подсвечивает соответствующие друг другу строки программы на С и Assembler.</p><p>0:00 Как программа на C считает числа Фибоначчи</p><p>2:28 Как скомпилировать и дизассемблировать программу</p><p>3:20 Разбор машинного кода</p>]]></content:encoded>
    </item>
    <item>
      <title>Для чего хорош Си?</title>
      <link>https://tproger.ru/articles/what-c-is-good-for</link>
      <comments>https://tproger.ru/articles/what-c-is-good-for?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/what-c-is-good-for</guid>
      <description><![CDATA[<p>Язык Си обычно используется в довольно сложных задачах. В каких? Отобрали для вас самые популярные области применения Си.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/what-c-is-good-for">Для чего хорош Си?</a>»</p>]]></description>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Для чего хорош язык X]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 28 Feb 2020 13:56:35 GMT</pubDate>
      <content:encoded><![CDATA[<p>Авторы: Dor Marciano, Мария Багулина</p><p>Си применяют в сферах, где важен код, наиболее тесно взаимодействующий с «железом». Под влиянием Си появились языки C++, C#, Java и Objective-C.</p><p>Си иногда называют подмножеством C++ или «C++ без классов», но это не совсем верно. Почему это не так, можно узнать в <a href="https://tproger.ru/articles/what-cpp-is-good-for/">статье про C++</a>.</p><p>Си поддерживает исключительно процедурное программирование. Никаких классов, ООП, наследования — только функции и структуры. К основным особенностям языка относятся:</p><ul><li>доступ к памяти через указатели (особые переменные, в которых хранится адрес объекта);</li><li>активное использование структур и объединений;</li><li>чистый стиль программирования (код проще отлаживать, но сложнее писать).</li></ul><p>Си обычно используется в довольно специфичных и сложных задачах, потому что более лёгкие задачи проще сделать с помощью высокоуровневых языков. Мы отобрали несколько наиболее популярных применений Си.</p><h2>Оптимизация участков кода на C++</h2><p>Объектно-ориентированные возможности C++ часто обходятся дороже, чем «чистый Си», так как расходуют больше ресурсов (в частности оперативной памяти). Поэтому иногда код в стиле Си может быть эффективнее. Если нужно заставить какой-либо алгоритм работать быстрее — используйте процедурный стиль и откажитесь от встроенных инструментов C++ для ООП, например от полиморфизма.</p><p>Но если нужна действительно высокая скорость, лучше переписать часть кода на ассемблере.</p><h2>Информационная безопасность</h2><p>Сюда относятся сложные хакерские приёмы. Среди них:</p><ul><li>Использование уязвимостей: переполнения буфера, двойные удаления (повреждения кучи).</li><li>Инъекция (сокрытие) кода. Если получить доступ к другому процессу, используя уязвимость, то можно спрятать свой код внутри чужого и заставить процесс выполнять его. Теперь скрытый код будет жить в «невинном» процессе, спрятанном от глаз пользователя.</li><li>Перехват (hooking). Если вы хотите мониторить чьи-то взаимодействия с системой (нажатие клавиш, открытие файлов), вам, как правило, нужно вызывать отслеживающий код всякий раз, когда пользователь что-то делает. Для этого вы заменяете какой-либо фрагмент API операционной системы вашим кодом.</li></ul><p>Почти для всех этих применений используется PIC код (position-independent code — код, не зависящий от адреса). Он может выполняться в любом месте памяти, независимо от того, где находится и кто его запустил. У PIC-кода нет доступа к глобальным переменным и таблицам, поэтому C++ для его написания не подойдёт (классам C++ нужны глобальные таблицы для реализации наследования).</p><h2>Код ядра</h2><p>Код, который выполняется в режиме ядра (kernel mode) имеет полный доступ к памяти и оборудованию: RAM, GPU, жёсткому диску. В режиме ядра работают:</p><ul><li>Аппаратные драйверы — здесь без доступа к железу не обойтись. Драйверы являются посредниками между пользовательским кодом (не в режиме ядра) и оборудованием.</li><li>Ядро операционной системы. На Си, кстати, написано множество ядер ОС, в том числе Unix и Android.</li></ul><p>Использовать для всего этого код на C++ почти невозможно, поскольку в режиме ядра нет доступа к тем же глобальным таблицам, о которых говорилось выше. Иногда в режиме ядра тоже необходим PIC код — например для загрузчика (bootloader). Загрузчик — самая первая программа, выполняющаяся при запуске ПК. Биос извлекает её из жёсткого диска, помещает в память и говорит процессору запустить эту часть памяти.</p><h2>Embedded-разработка</h2><p>Для программирования встраиваемых систем часто используется как Си, так и C++. Но Си имеет преимущество, поскольку позволяет разрабатывать встроенное ПО при ограниченных ресурсах — например когда у микроконтроллера очень мало RAM. Помимо Си также может пригодиться знание ассемблера (как вариант, ARM-ассемблера) для написания ассемблерных вставок, чтобы ещё больше оптимизировать код и получить доступ к специфичным инструкциям процессора.</p>]]></content:encoded>
    </item>
    <item>
      <title>Должен ли «настоящий» программист знать язык Си — отвечают эксперты</title>
      <link>https://tproger.ru/experts/is-c-a-must-learn-for-all-programmers</link>
      <comments>https://tproger.ru/experts/is-c-a-must-learn-for-all-programmers?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Никита Прияцелюк]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/experts/is-c-a-must-learn-for-all-programmers</guid>
      <description><![CDATA[<p>Эксперты объясняют, обязательно ли программисту знать Си, что дают его основы и где язык применяют: от ядра Linux до микроконтроллеров.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/experts/is-c-a-must-learn-for-all-programmers">Должен ли «настоящий» программист знать язык Си — отвечают эксперты</a>»</p>]]></description>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Обучение программированию]]></category>
      <category><![CDATA[Ответы экспертов]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 02 Dec 2019 10:03:29 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ходит легенда, что знание Си сильно прокачивает навыки программиста, даёт ему глубокое понимание работы компьютерных систем и густую бороду. О том, так ли это и нужно ли всем программистам в обязательном порядке учить Си, мы спросили у экспертов.</p><p>Да, сейчас запросов на разработку современных продуктов на языке С относительно немного. Как показывает наш портфель проектов, выше спрос на С++. Однако, в программисте мы видим, прежде всего, инженера, способного разобраться со сложными вопросами, которые, возможно, до него ещё никто не решал. Поэтому знание основ С — это плюс для общеинженерного развития специалиста.</p><p>В современной индустрии преобладает разработка с использованием объектно-ориентированного программирования (ООП), язык Си — процедурный и сейчас стал «нишевым». Он используется в областях, где существуют жесткие требования к производительности, или аппаратные ресурсы платформы сильно ограничены. Примером может стать ядро Linux или программирование микроконтроллеров.</p><p>В мобильной разработке язык Си может использоваться при написании игр или для создания native методов Java классов, реализация которых использует вызовы JNI.</p><p>Язык Си считается языком низкого уровня. Начав изучение программирования с него, специалист будет лучше понимать базовые вещи в разработке. Кроме того, существует множество языков программирования, синтаксис которых берёт начало у языка Си, например C++, Java, C#. Знание «первоисточника» наверняка облегчит их изучение.</p><p>Тем не менее, базу (классические структуры данных, битовые операции) можно изучать на примерах ООП-языков, особой разницы нет. Кроме того, зачастую такой уровень погружения в детали, который даёт Си, на практике не нужен.</p><p>Программист высокого уровня должен иметь широкий кругозор и не замыкаться в рамках одной парадигмы программирования или языка. Сегодня в России не так много специалистов, хорошо владеющих «низкими» языками программирования, а знание Си может стать важным конкурентным преимуществом.</p><p>«Настоящему» программисту стоит понимать концепции, которые лежат в основе языка Си — как работает управление памятью, указатели, структуры. Здесь можно провести аналогию: нужно ли знать водителю устройство автомобиля? Если человек хочет просто перемещаться из точки в точку, то ему вряд ли пригодятся такие знания в полной мере. А вот если он хочет стать хорошим водителем, то с некоторыми принципами работы автомобиля всё же придётся разобраться.</p><p>Однако изучать базу можно и на примере других языков. Возможностей очень много, поэтому знать именно язык Си совсем не обязательно.</p><p>Изучать какой-либо язык программирования, не имея планов по дальнейшему применению этих знаний на практике, к сожалению, бессмысленная затея. Знания, не подкреплённые практикой, как минимум будут неполными, ну а как максимум — «улетучатся» через полгода-год.</p><p>Если есть интерес заглянуть поглубже и понять работу компьютерных систем, надо ориентироваться не столько на язык, сколько на разработку какого-либо системного программного обеспечения. Например написать собственный драйвер под какое-либо устройство (например подключаемое через USB). В процессе работы над подобной задачей потребуется изучить, каким образом происходит взаимодействие операционной системы и внешнего устройства, особенности системных API и протоколов и многое другое.</p><p>Несколько реализованных проектов по разработке системного ПО разных классов — и у вас уже будет не только понимание базовых принципов функционирования операционных систем, но и ценный практический опыт. Естественно, реализация будет на языке C/С++!</p><p>Для изучения базовых структур данных и алгоритмов подойдет большинство языков программирования. Для какой-то конкретной области — наоборот, понадобится знание определённого языка. И маловероятно, что это будет именно Cи. Так что на этот вопрос нет однозначно правильного ответа. «Настоящий» программист — это любой человек, который пишет код и получает за это деньги. И большинство таких ребят начинали с совершенно разных языков. Всё остальное — это темы холиваров, не более.</p><p>Но сам вопрос — острый, и фокус в нём вовсе не на Cи, а на том, какую технологию выбрать для изучения сейчас, чтобы принимать участие в реальных проектах в будущем. Конечно, верный ответ тут: «любую».</p><p>Ведь язык — это лишь инструмент для человека, который знает математику, алгоритмы и архитектуру систем. Но на этапе обучения хочется конкретики. Учить что-то сейчас — лучше, чем не учить ничего, но многообразие технологий пугает.</p><p>Я считаю, что Cи как первый язык — это неудачный выбор. Там нет ни одной интересной парадигмы. Все аргументы вроде «Cи — основа основ», «Cи самый быстрый», «Cи позволяет лучше понимать базовые вещи» не выглядят убедительными. Си важный язык для определённых экосистем, например микроконтроллеров, утилит и ядра ОС, драйверов, встраиваемых систем и т. п. Но это довольно узкие области. Человек, который учит Си конкретно для этих кейсов, обычно не руководствуется понятиями «трушности» технологии.</p><p>Для обучения на первоначальном этапе я бы посоветовал рассматривать Java или C++, у них хорошая ООП-парадигма и много интересных новинок в стандартах. Кроме того, они более универсальные и востребованные. В C++ порог входа чуть выше. Также неплохим вариантом будет изучение JavaScript. По тем же причинам.</p><p>Да, действительно, в ряде случаев изучение C/С++ улучшает понимание того, как работает компьютер и способствует значительному улучшению качества кода, написанного даже на других языках. Особенно это полезно программисту, для которого единственным известным языком является какой-нибудь достаточно высокоуровневый язык (Python, JavaScript, PHP). С другой стороны, возможно, вы уже знакомы с основами работы компьютера и не собираетесь программировать на C/C++. Тогда терять время на изучение этих языков не стоит. Можно легко проверить себя, ответив на вопросы ниже. Если вы чётко представляете ответы на них, то, скорее всего, C/C++ вам нужно изучать, только если вы собираетесь писать программы именно на этих языках:</p><ol><li>Как сложные объекты передаются в функции в известном мне языке программирования? Сколько времени и памяти тратится при такой передаче?</li><li>Как рассчитать требуемый объём стека для рекурсивной функции, если известна максимальная глубина рекурсии?</li><li>Что такое выделение и освобождение памяти? Где в моей программе память выделяется, а где освобождается? Как спрогнозировать, сколько памяти будет потреблять моя программа?</li><li>Что такое полиморфизм в объектно-ориентированном программировании?</li><li>Что такое шаблоны (паттерны) проектирования программ? Известны ли вам какие-нибудь из них?</li></ol><p>Язык Си действительно один из самых старых и популярных инструментов для разработки ПО. Его используют там, где необходима высокая производительность и низкоуровневая работа с железом: системное программирование, работа с микроконтроллерами, разработка операционных систем. Очевидно, что программисты, работающие над ПО такого рода, должны хорошо знать свой основной инструмент.</p><p>Обязательно ли знать Си современному веб- или мобильному разработчику? Я думаю, что нет. В большинстве случаев в ежедневной разработке знание Си ему не потребуется. С другой стороны, будет ли вредно понимание основ и концепций этого языка? Точно нет. Я уверен, что интересы «настоящего» программиста (в моем субъективном понимании) должны выходить за пределы ежедневной рутины.</p><p>Поэтому, я считаю, что трата времени на изучение основ этого языка — это долгосрочная инвестиция в своё профессиональное образование. Конечно, с оговоркой на то, что при выборе глубины изучения нужно руководствоваться здравым смыслом.</p><p>Не должен.</p><p>Но попробовать стоит! Любой язык программирования — это инструмент для решения определённого круга задач. Чем большим количеством инструментов ты владеешь, тем больше разнообразных проблем ты можешь решить, а, следовательно, тем более ценным специалистом ты являешься. А если ты в начале своего пути в профессии, то тут как в бурной молодости: нужно попробовать всё, чтобы решить, что твоё, а что — нет.</p><p>Изучение Си действительно способствует пониманию многих фундаментальных вещей. Лично я в университете знакомство с алгоритмами и структурами данных начинал именно на Си, потому что программирование на таком низкоуровневом языке помогает разобраться во всех нюансах, которые инкапсулированы в современных языках высокого уровня, и лучше понимать, как работают приложения.</p><p>Но в большинстве современных задач эти нюансы знать совершенно не обязательно: практически для каждого языка есть большое количество надёжных фреймворков, ставших отраслевыми стандартами, которые освобождают разработчика от низкоуровневых операций, и на первый план выходит знание подходов к разработке и архитектурных паттернов.</p><p>Си — это язык, который сейчас имеет свою большую нишу: он используется в операционных системах и системах реального времени, область применения которых очень широка — от IoT до управления самолетами. Если такой «хард и металл» — это то, чем вы хотите заниматься, учить Си нужно, но в других сферах деятельности гораздо эффективнее разрабатывать на других языках, и там знание Си, скорее всего, никак не поможет.</p><p>Однозначно можно сказать только то, что грести всех под одну гребёнку неверно. И разделение на «настоящих» и «ненастоящих» программистов — одна из попыток людей систематизировать то, что не только не поддаётся систематизации, но и не нуждается в ней. Абсолютно равнозначным в этой ситуации будет такой вопрос: «Должен ли “настоящий” программист С знать другие языки?». Да, С — это старый, завоевавший уважение язык, повлиявший на многие другие, но в 2019-м году нет явной необходимости его учить, чтобы уметь программировать, закрывать задачи бизнеса или понимать внутренние процессы в приложениях. Знание С и умение, например, работать с указателями, помогает в работе, это факт. Очень сильно помогает быстро выучить какой-нибудь С-подобный язык, это тоже правда. Организует и приучает к строгости, возможно. Но так, чтобы «должен, иначе не настоящий программист» — вряд ли.</p><p>В своей практике (кроме периода, когда я профессионально разрабатывал на С/С++) я несколько раз сталкивался с ситуациями, когда проще написать на С/С++, чем на каком-то другом языке, но я абсолютно уверен, что это скорее исключения, чем что-то происходящее с людьми часто. Информационные технологии развиваются гораздо динамичнее, чем это может себе позволить любой язык программирования, тем более такой архаичный, как С, поэтому и появляются новые языки, выполняющие поставленные перед ними задачи лучше других. Да, разработчики этих новых языков зачастую используют С «под капотом», но программисту знать об этом нужно в исчезающе малом количестве случаев.</p><p>Я убеждён, что разговор о «настоящих» и «ненастоящих» программистах заводят две категории людей: сами программисты С, потому что очень сильно гордятся своим знанием сложного и старого языка, стоявшего у истоков, и люди, ничего не понимающие в программировании, но по какой-то причине вынужденные взаимодействовать с программистами. Для них так проще отличить хорошего программиста от плохого, не вдаваясь в детали. Знаешь С — хороший, не знаешь С — плохой. Не поймите меня неправильно, первым действительно есть чем гордиться, а вторым действительно не нужно вникать в детали. Но всегда нужно двигаться вперёд, и если это движение не связано с конкретным языком программирования, что ж, значит так нужно миру, бизнесу и технологиям, а если вам позарез нужно проверить квалификацию программиста, лучше спросите его об алгоритмах и паттернах.</p><p>Ответ на этот вопрос будет зависеть, прежде всего, от области разработки: например веб-разработчику знание языка С в его профессиональной карьере пригодится навряд ли.</p><p>При этом разработчики по мере роста своего профессионализма в области разработки ПО неизбежно приходят к необходимости изучения С, поскольку на этом языке написан огромный массив кода, лежащий в основе множества современных ИТ-продуктов и систем. И даже в тех случаях, когда речь не идёт о непосредственном использовании С, идеи этого языка так или иначе применялись в других языках, его влияние переоценить невозможно.</p><p>С другой стороны, С несёт в себе врожденную сложность — требует от программистов глубокого понимания архитектуры компьютеров, адресной арифметики и ряд других моментов, что очень полезно для общего развития специалиста.</p><p>Можно говорить, что если разработчик не испытывает проблем с пониманием адресной арифметики, то он может мыслить системно и делает это серьёзном уровне, а значит, в теории сможет решать более комплексные практические задачи.</p><p>В целом же общемировой тренд разработки направлен на упрощение труда программиста таким образом, чтобы получать от специалиста наименьшего уровня квалификации наивысший возможный продаваемый результат. На этот тренд работает и автоматизация ряда задач разработки с помощью высокоинтеллектуальных инструментов. С в этом свете выглядит как наследие первых поколений разработчиков, среди которых было множество серьёзных математиков.</p><p>Сейчас кадров с таким бэкграундом в подготовке становится всё меньше, поэтому заявление «если не знаешь С — то ты не программист» теряет актуальность. Прикладные задачи можно спокойно решать и без системного понимания сферы ИТ и места в ней поставленной задачи.</p><p>Наверное, стоит начать с того, что такое «настоящий программист». Ещё не так давно программисты практически не разделялись по своей специализации — ну, разве что по языкам. Тем не менее, наиболее сложным видом программирования считалось системное программирование, которое и сегодня почти невозможно без знания С (а также ассемблера и микроархитектуры железа, что, несомненно, тоже должно было входить в арсенал «настоящего программиста»).</p><p>С другой стороны, сейчас существуют совершенно несвязанные друг с другом области работы программистов; специалист в области BigData должен иметь другую квалификацию, нежели специалист в области внедрения ERP. Соответствующим образом разделяются и требования к «настоящему программисту», например «настоящий программист» в области искусственного интеллекта не может не знать математику. Поэтому если вы не знаете С — не переживайте, вы всё ещё вполне можете себя найти, скажем, в качестве frontend разработчика.</p><p>Программисту может потребоваться знание языка C в зависимости от специфики его задач. Например, если программист пишет драйверы для операционной системы, скорее всего ему нужно знать C и Assembler. Если он разрабатывает веб-интерфейсы и программирует сайты, ему точно не пригодится этот язык.</p><p>Если же говорить о программистах-разработчиках-исследователях, которые пишут не просто реализацию какого-то известного подхода, то скорее уместно говорить о Python и С++. Первый хорошо подходит для прототипирования, а последний часто используется в продакшн-коде крупных компаний. У нас это основные языки программирования, в целом всё зависит от того, в какой отдел и на какую позицию приходит работать человек. Сейчас язык C встречается мало где, но есть ниши, где требуется знание именно этого языка. Однако лично я не считаю C обязательным языком для каждого программиста.</p><p>Есть очень много высокоуровневых языков: для Ruby on Rails, например, достаточно 3–4 месяца, чтобы его освоить хотя бы на базовом уровне. Си — более академический язык, и даёт фундамент для понимания, как работают другие языки. Люди с опытом в Си имеют больше фундаментальных знаний, а также представление о том, как устроены языки программирования, и какие операции и логика будут/могут влиять на память, CPU и другие компоненты приложения и железа. Это связано с тем, что данный язык требует большого внимания к этим деталям и позволяет через код влиять на них. Тратить или не тратить время на изучение — решает каждый сам в зависимости от своих целей. Если говорить о разработке промышленных решений, то знание языка Си пригодится. Если речь идёт о разработке сайтов, панелей админок и небольших стартапов — то знаний других языков будет достаточно.</p><p>Если человек хочет стать хорошим строителем, он должен знать, как устроен дом: понимать, как делается кирпичная кладка, какие материалы нужно использовать, чтобы дом выдержал все катаклизмы природы, а также то, как сделать дом удобным и безопасным для будущих новосёлов. По этой же причине хороший программист должен понимать, как устроены базовые алгоритмы, а также какие и в каком количестве программа потребляет системные ресурсы. Для этого наилучшим образом подходит язык Си, где взаимодействие с машиной происходит на достаточно низком уровне, но который, в отличие от языка Ассемблера, обладает всё теми же конструкциями, что и большинство языков более высокого уровня.</p><p>Кто-то становится журналистом, кто-то писателем, а кто-то учёным. Понятно, что все эти профессии объединяет одно — способность чётко и правильно выражать свои мысли: журналисту — в публицистическом стиле, писателю — в художественном, учёному — в научном. Точно так же и изучение Си способствует вырабатыванию собственного стиля, который может быть применён в дальнейших языках, специализирующихся на своих задачах. Знания Си одинаково полезны будут и системному программисту, и прикладному, и веб-технологу. Стоит только вспомнить, какие языки используют похожий синтаксис: C++, C#, Java, JavaScript, PHP, Perl, AWK. И многие другие.</p><p>Ещё один аргумент в пользу того, чтобы начать изучение программирования именно с Си, заключается в том, что этот язык не прощает ошибок. Здесь не получится небрежно обойтись с памятью, уповая на сборщика мусора или на то, что интерпретатор пропустит мимо выход за пределы массива. Здесь нет ни интерпретатора, ни сборщика мусора. Поэтому такие ошибки будут сразу видны, и в сотый раз получив сообщение от операционной системы Segmentation fault, ученик начнёт задумываться, что, в конечном счёте, приведёт к формированию правильного стиля кода и поможет ему в дальнейшем в освоении новых языков.<br />Конечно, освоивший Си с лёгкостью перейдёт на более высокоуровневые инструменты, но навык хорошего стиля, при достаточном уровне проработки на Си, у такого ученика останется навсегда. А если ученик особо пытливый, он захочет разобраться, как именно исполняется его программа на вычислительной машине и откроет скомпилированный файл в дизассемблере. Благодаря тому, что Си не оброс большим количеством наслоений и абстракций, не составит большого труда сопоставить полученный код с тем, что было изначально. А это первый шаг к изучению языка ассемблера. Сделав такой шаг, ученик встаёт уже на путь системного программиста, программиста микроконтроллеров или исследователя программ. Удивительный мир низкого уровня особенно понравится перфекционистам, которые захотят досконально изучить принципы функционирования вычислительной машины и полностью контролировать её.</p><p>Недаром язык Си называет в шутку «кроссплатформенным ассемблером». И хотя словосочетание само по себе является оксюмороном, доля правды в этой шутке всё же есть. Например, интерфейс системных вызовов в UNIX-подобных операционных системах осуществлён именно с использованием библиотек Си. На этом языке также разрабатываются операционные системы, драйверы, программное обеспечение для микроконтроллеров, на этом языке пишутся компиляторы и трансляторы. Компилятор gcc, используемый для компиляции программ на Си — одна из главных программ, входящая в базовую комплектацию любого дистрибутива Linux, поскольку сборка остальных пакетов и модулей происходит путём компиляции исходников именно на этом языке. Стоит также отметить, что большинство технологий и средств разработки более высокого уровня изначально были написаны на Си: интерпретируемые языки вроде Python, Perl и PHP, виртуальная машина Java и многое другое.<br />Время выполнения того или иного алгоритма и потребление им памяти максимально «честно» можно вычислить именно на языке Си, ведь никаких дополнительных накладных расходов при выполнении программы не происходит. Вот почему это особенно полезно для проверки себя на правильность реализации тех или иных алгоритмов. В учебной программе бакалавриата МАИ уже пять лет успешно изучается курс Си, вытеснив собой язык Pascal. И хотя Pascal даёт возможность понять работу основных алгоритмов, в нём многие ошибки контролируются на уровне синтаксиса. Вот почему важно делать много ошибок на самом начальном этапе, разбирать их, контролировать и не допускать в будущем. Также важно понимать не только ход работы алгоритма, но и представлять, сколько такой алгоритм потребляет системных ресурсов. Классический синтаксис важно изучить, чтобы не возникло проблем с изучением других технологий в будущем. Вот главные причины, почему стоит начать изучение программирования с этого замечательного языка.</p><h2>Итак, должен ли тру-программист знать Си?</h2><p>В общем и целом, эксперты сошлись на мнении, что не должен.</p><p>Си может дать более глубокое понимание того, как работают другие языки, как код влияет на железо и так далее. Однако, нужно ли вам это глубокое понимание в обязательном порядке? Сейчас существует много языков и много направлений в разработке, где Си либо не нужен, либо нужен редко. Да, есть определённый круг задач, где знание Си необходимо. Но мы ведь говорим не про отдельные кейсы, а про всех программистов в целом?</p><p>С другой стороны, программирование на таком низкоуровневом языке помогает разобраться во всех нюансах, которые инкапсулированы в современных языках высокого уровня, поэтому Си можно изучать для саморазвития и повышения своего профессионального уровня.</p><p>Но всё-таки, в первую очередь учите те языки, которые нужны для решения ваших задач, а остальные оставьте для общего развития.</p><p>Напоминаем, что вы можете <a href="https://docs.google.com/forms/d/e/1FAIpQLSdSanNvlfPRrSyQWfnoGPflSVwO4KctnjOdEKHzuxjCmFX2dA/viewform">задать свой вопрос</a> экспертам, а мы соберём на него ответы, если он окажется интересным. Вопросы, которые уже задавались, можно найти в списке выпусков <a href="https://tproger.ru/experts/">рубрики</a>. Если вы хотите присоединиться к числу экспертов и прислать ответ от вашей компании или лично от вас, то пишите на <a>experts@tproger.ru</a>, мы расскажем, как это сделать.</p>]]></content:encoded>
    </item>
    <item>
      <title>Реверс-инжиниринг для начинающих: продвинутые концепции программирования</title>
      <link>https://tproger.ru/translations/reverse-engineering-concepts</link>
      <comments>https://tproger.ru/translations/reverse-engineering-concepts?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Туренко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/reverse-engineering-concepts</guid>
      <description><![CDATA[<p>Массивы, указатели, динамическое распределение памяти, сокеты и многопоточность в дизассемблированном коде — вторая часть с примерами на IDA Pro.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/reverse-engineering-concepts">Реверс-инжиниринг для начинающих: продвинутые концепции программирования</a>»</p>]]></description>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Низкоуровневое программирование]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 31 Mar 2019 08:47:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>В <a href="https://tproger.ru/translations/reverse-engineering-basics/">первой части</a> мы рассмотрели базовые концепции программирования, такие как циклы и условный оператор, в этой статье будем рассматривать более сложные темы, необходимые для реверс-инжиниринга.</p><p>Примечание Для дизассемблирования в этой статье используется IDA Pro, но многие её функции (например блок-схемы, перевод в псевдокод и т. д.) можно найти в качестве надстроек в бесплатных дизассемблерах (radare2). Более того, для лучшего понимания имена некоторых дизассемблированных переменных были изменены с «v20» на имена, которые были у них в С. Также в этой статье исполняемый файл был скомпилирован в 64-битной версии, а для дизассемблирования используется 64-битная версия IDA Pro. Это на случай, если вы захотите повторить всё самостоятельно, потому что это может повлиять на конечный результат (например, на массивах будет сильное различие 32 и 64-битных версий, а также в 64-битной версии регистры становятся в два раза больше).</p><h2>Массивы</h2><p>Итак, начнём с массивов. Сначала рассмотрим код на Си:</p><p>Эти 12 строк кода превращаются в довольно внушительный блок машинного кода. Давайте рассмотрим его детально:</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-2.jpeg" alt="" /></figure><p>При инициализации массива с константным размером компилятор просто инициализирует длину массива через локальную переменную.</p><p>Во время компиляции будет выделено место только под одно значение массива litArray[0], которое и будет использоваться (можно увидеть на скриншоте ниже). Такой приём позволяет компилятору значительно увеличить производительности приложений.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-3.jpeg" alt="" /></figure><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-4.jpeg" alt="" /></figure><p>Сначала длина массива сохраняется в локальную переменную ArraySize, затем вычисляется максимальное и минимальное индексное значение, а также длина всего массива, а затем под неё выделяется память.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-5.jpeg" alt="" /></figure><p>При объявлении массива с предопределёнными значениями компилятор сохраняет каждое значение в свою переменную, которая представлена индексом массива (например objArray4 = objArray[4]).</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-6.jpeg" alt="" /></figure><p>Так же как и с предопределёнными значениями, компилятор создаёт новую переменную для указанного индексного значения при инициализации элемента массива через индекс.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-7.jpg" alt="" /></figure><p>При извлечении элемента массива значение элемента берётся по указанному индексу и записывается в нужную переменную.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic8.jpeg" alt="" /></figure><p>При создании матрицы сначала её размер устанавливается в соответствии со значениями row и col. Затем рассчитываются максимальный и минимальный индексы для строк и столбцов, которые используются для расчёта базового местоположения и общего размера матрицы в памяти.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-9.jpeg" alt="" /></figure><p>При вводе в матрицу сначала определяется местоположение желаемого элемента массива с использованием базового местоположения матрицы. Затем содержимое указанного элемента массива устанавливается на желаемое входное значение (т.е. 1337).</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-10.jpeg" alt="" /></figure><p>При извлечении значения из матрицы происходят такие же вычисления, как и при внесении значения в неё. Однако при этом ничего не записывается — содержимое извлекается и записывается в нужную переменную (например MatrixLeet).</p><h2>Указатели</h2><p>Теперь, когда мы понимаем, как массивы используются и выглядят в машинном коде, давайте перейдём к указателям.</p><p>Давайте сразу разберёмся в машинном коде:</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-11.jpeg" alt="" /></figure><p>Сначала мы присваиваем переменной num значение 10.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-12.jpeg" alt="" /></figure><p>Затем указателю pointer присваивается адрес переменной num.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-13.jpeg" alt="" /></figure><p>Вывод переменной num на экран.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-14.jpeg" alt="" /></figure><p>Вывод переменной pointer на экран.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-15.jpeg" alt="" /></figure><p>Вывод адреса переменной num происходит с помощью инструкции lea (загрузка результирующего адреса) вместо mov.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-16.jpeg" alt="" /></figure><p>Вывод адреса переменной num через указатель pointer.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-17.jpeg" alt="" /></figure><p>Вывод адреса переменной pointer происходит с помощью инструкции lea вместо mov.</p><h2>Динамическое распределение памяти</h2><p>В этой статье будут рассмотрены следующие виды динамического распределения памяти:</p><ol><li>malloc.</li><li>calloc.</li><li>realloc.</li></ol><h3>malloc — динамическое выделение памяти</h3><p>Сначала разберёмся в коде:</p><p>Прим. перев. В оригинале статьи выделяется 11 байтов, хотя правильно будет 12. В конце строки ещё добавляется символ с кодом 0.</p><p>В этой функции выделяется место под 11 символов с помощью malloc(), а затем в выделенное пространство памяти копируется «Hello World».</p><p>Теперь давайте посмотрим на машинный код:</p><p>Примечание Во время сборки вы можете увидеть инструкции «nop». Эти инструкции были специально размещены на этапе подготовки к статье, чтобы различные части кода было проще понимать.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-18.jpeg" alt="" /></figure><p>При использовании malloc() размер выделенной памяти (0x0B) сначала перемещается в регистр edi. Затем системная функция _malloc вызывается для выделения памяти. Выделенная область памяти затем сохраняется в переменной ptr. Потом строка «Hello World» разбивается на «Hello Wo» и «rld», поскольку она копируется в выделенное пространство памяти. Наконец, вновь скопированная строка «Hello World» выводится на экран, а выделенная память освобождается с помощью функции _free.</p><h3>calloc — динамическое чистое выделение памяти</h3><p>Посмотрим на код:</p><p>Как и в методе malloc(), место для 11 символов выделяется, а строка «Hello World» копируется в указанное пространство. Затем вновь перемещённый «Hello World» распечатывается, и выделенное пространство памяти освобождается.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-19.jpeg" alt="" /></figure><p>Динамическое распределение памяти через calloc() выглядит почти идентично динамическому распределению памяти через malloc() в машинном коде.<br />Во-первых, пространство для 11 символов (0x0B) выделяется с помощью системной функции _calloc. Затем строка «Hello World» разбивается на «Hello Wo» и «rld„, поскольку она копируется во вновь выделенную область памяти. Затем вновь перемещённая строка “Hello World» выводится на экран, а выделенная область памяти освобождается с помощью функции _free.</p><h3>realloc — динамическое перераспределение памяти</h3><p>Сначала посмотрим код.</p><p>В этой функции память для 11 символов выделяется с помощью malloc(). Затем «Hello World» копируется в только что выделенное пространство памяти, прежде чем указанное расположение памяти перераспределяется, чтобы соответствовать 21 символу.</p><p>Прим. перев.: Должно быть 22 символа. Снова автор забыл символ с кодом 0, используя realloc()</p><p>Наконец, «1337 h4x0r @nonymoose» копируется в только что перераспределённое пространство. Наконец, после вывода на экран память освобождается.</p><p>Теперь посмотрим машинный код:</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-20.jpg" alt="" /></figure><p>Сначала память выделяется с помощью malloc(). Затем, после вывода на экран только что перемещённой строки «Hello World», вызывается realloc() для переменной ptr (которая представляет переменную mem_alloc в коде), а также передаётся новый размер 0x15 (21 в десятичном виде). Затем «1337 h4x0r @nonymoose» разбивается на «1337 h4x„, “0r @nony», «moos» и «e„, поскольку он копируется в только что перераспределённое пространство памяти. Наконец, пространство освобождается с помощью функции _free.</p><h2>Программирование сокетов</h2><p>Далее мы рассмотрим программирование сокетов, разобрав очень простую систему клиент-серверного TCP-чата.</p><p>Прежде чем мы начнём разбирать код сервера или клиента, важно указать следующую строку кода в верхней части файла:</p><p>Эта строка определяет константу PORT как 1337. Эта константа будет использоваться как на клиенте, так и на сервере в качестве сетевого порта, используемого для создания соединения.</p><h2>Серверная часть</h2><p>Сначала посмотрим на код:</p><p>Сначала создаётся файловый дескриптор сокета server с доменом AF_INET, типом SOCK_STREAM и кодом протокола 0. Далее настраиваются параметры сокета и адрес. Затем сокет привязывается к сетевому адресу (порту), и сервер начинает прослушивать указанный порт с максимальной длиной очереди 3. После получения соединения сервер принимает его в переменную sock и считывает переданное значение в переменную value.</p><p>Наконец, сервер отправляет строку serverhello по соединению до возврата функции.</p><p>Теперь давайте разберём его в машинном коде:</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-21.jpeg" alt="" /></figure><p>Сначала создаются и инициализируются переменные сервера.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-22.jpeg" alt="" /></figure><p>Затем создаётся файловый дескриптор сокетов server с помощью системной функции _socket. Параметры для функции — протокол, тип и доменное имя передаются с помощью регистров edx, esi и edi соответственно.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-23.jpeg" alt="" /></figure><p>Затем вызывается _setsockopt для задания параметров сокета в файле дескриптора “server».</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-24.jpg" alt="" /></figure><p>Инициализируется серверный адрес с помощью adress.sin_family, address.sin_addr.s_addr и address.sin_port.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-25.jpg" alt="" /></figure><p>После того как сервер был сконфигурирован, он привязывается к интернет-адресу с помощью _bind.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-26.jpeg" alt="" /></figure><p>После привязки сервер слушает сокет, передав файловый дескриптор server. Максимальная длина очереди равна 3.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-27.jpg" alt="" /></figure><p>Как только соединение установлено, сервер принимает соединение сокета в переменную sock.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-28.jpeg" alt="" /></figure><p>Затем сервер считывает переданное в переменную value сообщение с помощью _read.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-29.jpeg" alt="" /></figure><p>В конце концов, сервер отсылает сообщение serverhello через переменную s в машинном коде.</p><h2>Клиентская часть</h2><p>Сначала разберёмся в коде:</p><p>Сначала создаётся файловый дескриптор сокета sock с помощью переменной домена AF_INET типа SOCK_STREAM и кода протокола 0. Затем memset используется для заполнения области памяти server_addr нулями до того, как информация об адресе будет установлена ​​с помощью server_addr.sin_family и server_addr.sin_port. До того как клиент подключится к серверу, информация об адресе преобразуется из текстового в двоичный формат с использованием inet_pton. После подключения клиент отправляет строку helloclient и затем принимает ответ сервера в переменную value. Наконец, переменная value выводится на экран, и происходит возврат из функции.</p><p>Теперь разбёремся в машинном коде:</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-29.jpg" alt="" /></figure><p>Сначала инициализируются локальные переменные клиента.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-30.jpeg" alt="" /></figure><p>Дескриптор файла сокета «sock» создается путём вызова системной функции _socket и передачи информации о протоколе, типе и домене через регистры edx, esi и edi соответственно.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-31.jpeg" alt="" /></figure><p>Переменная server_address (в машинном коде «s») заполняется нулями (0x30) с помощью системного вызова _memset.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-32.jpeg" alt="" /></figure><p>Потом настраивается адресная информация сервера.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-33.jpeg" alt="" /></figure><p>Затем адрес переводится из текстового в двоичный формат с помощью системной функции _inet_pton. Обратите внимание, что, поскольку в коде явно не указан адрес, предполагается localhost (127.0.0.1).</p><p>Клиент подключается к серверу с помощью системного вызова _connect.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-35.jpeg" alt="" /></figure><p>После подключения клиент отправляет строку helloClient на сервер.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-36.jpeg" alt="" /></figure><p>Наконец, клиент получает ответ сервера в переменную value с помощью системного вызова _read.</p><h2>Многопоточность</h2><p>Наконец, мы рассмотрим основы потоков в C.</p><p>Во-первых, давайте посмотрим на код:</p><p>Как вы можете видеть, программа сначала печатает «This is before the thread», затем создаёт новый поток, который указывает на функцию *mythread(), используя функцию pthread_create(). По завершении функции *mythread() (после сна длиной в 1 секунду и вывода на экрана «Hello from mythread») новый поток присоединяется к основному потоку с помощью функции pthread_join() и выводится на экран «This is after the thread».</p><p>Теперь давайте разберём машинный код:</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-37.jpeg" alt="" /></figure><p>Сначала программа печатает «This is before the thread».</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-38.jpeg" alt="" /></figure><p>Затем создаётся новый поток с помощью системного вызова _pthread_create. Этот поток получает mythread() в качестве аргумента.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-39.jpeg" alt="" /></figure><p>Как вы можете видеть, функция mythread() просто спит одну секунду перед выводом «Hello from mythread».</p><p>Примечание Внутри функции mythread() вы увидите два нопа. Они были специально размещены для облегчения навигации на этапе подготовки этой статьи.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-40.jpeg" alt="" /></figure><p>После возврата из функции mythread() новый поток соединяется с основным потоком с помощью функции _pthread_join.</p><figure><img src="https://media.tproger.ru/uploads/2019/03/reverse-dev-pic-42.jpeg" alt="" /></figure><p>Наконец, на экран выводится «This is after the thread» и происходит возврат из функции.</p><h2>Заключение</h2><p>В статье мы рассмотрели массивы, указатели, динамическое распределение памяти, программирование сокетов (сетевое программирование) и многопоточность. Понимание этих аспектов существенно поможет вам продвинуться в изучении реверс-инжиниринга.</p>]]></content:encoded>
    </item>
    <item>
      <title>Видеокурс для изучения языка Си с нуля</title>
      <link>https://tproger.ru/video/clang-for-beginners-videos</link>
      <comments>https://tproger.ru/video/clang-for-beginners-videos?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Грачев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/video/clang-for-beginners-videos</guid>
      <description><![CDATA[<p>Русскоязычный видеокурс знакомит новичков с основными конструкциями языка Си; в уроках используют Ubuntu, GCC, Sublime Text и Visual Studio Code.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/video/clang-for-beginners-videos">Видеокурс для изучения языка Си с нуля</a>»</p>]]></description>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Обучение программированию]]></category>
      <category><![CDATA[Обучающие курсы]]></category>
      <category><![CDATA[Видео]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 08 Jan 2019 18:26:27 GMT</pubDate>
      <content:encoded><![CDATA[<p>Язык Си был разработан в 70-е годы XX века Деннисом Ритчи, сотрудником исследовательского центра Bell Labs. Язык отличается несложным синтаксисом, возможностью писать код на низком уровне абстракции, а также компактным размером стандартной библиотеки. Поэтому на нём до сих пор пишут программы для микроконтроллеров, драйвера устройств, промышленное ПО и многое другое.</p><p>Чтобы вы смогли изучить Си с нуля, мы нашли интересный видеокурс на русском языке, подробно объясняющий основные конструкции и другие элементы языка. Автор видеоуроков в качестве рабочей среды использует ОС Ubuntu, компилятор GCC и редакторы кода Sublime Text и Visual Studio Code. Каждый видеоурок длится в среднем 25−30 минут, в течение которых подробно разбирается каждая тема. Курс ориентирован на тех, кто никогда не сталкивался с программированием.</p><h3>Содержание курса</h3><ol><li><a href="https://youtu.be/jCDvTH5Bn04">Введение в язык, создание первой программы</a><br />Автор приводит историю языка, объясняет некоторые базовые понятия и создаёт простейшую программу на Си.</li><li><a href="https://youtu.be/OTXHSdYNLcA">Переменные, создание переменных в языке Си</a><br />В данном видео рассказывается о типах переменных (short, int, char, float, double, long, long long) и методах их создания.</li><li><a href="https://youtu.be/D0-VeNiU6ZM">Переменные, ввод и вывод информации в терминале в языке Си</a><br />В видеоролике говорится о том, как ввести и вывести через терминал значения переменных с помощью функций scanf() и printf().</li><li><a href="https://youtu.be/jgci-F3hVkA">Escape-последовательности</a><br />Escape-последовательности представляют собой сочетания символов, начинающиеся с косой черты и представляющие собой цифру или букву, например \n, \t. Автор рассказывает, какие escape-последовательности существуют, за что они отвечают и как используются в программе.</li><li><a href="https://youtu.be/s2SutHVCn-Y">Арифметические операции</a><br />Видео посвящено разбору различных арифметических операций, принятых в языке.</li><li><a href="https://youtu.be/O9E7VPYF4XE">Составные операции в языке Си</a><br />В Си можно использовать составное присваивание значений, например, с помощью +=, -=, *= и /=. В видео подробно разбираются эти конструкции, а также показывается их использование на примерах программ.</li><li><a href="https://youtu.be/SMxa4vPIm1o">Локальные и глобальные переменные в языке Си</a><br />Автор рассказывает о том, чем отличаются глобальные и локальные переменные, а также знакомит с ключевыми словами extern и static.</li><li><a href="https://youtu.be/ShRItTgWpYw">Преобразование типов данных в языке Си</a><br />В видео объясняется, как привести переменные к другим типам данных, например int к float.</li><li><a href="https://youtu.be/SPp2tsIQUQI">Массивы, создание массивов в языке Си</a><br />Из видео вы узнаете, что такое массив, как его создать на языке Си и как выполнять действия с его элементами. Рассматривается только одномерный массив.</li><li><a href="https://youtu.be/MaUVirfsCqU">Многомерные массивы, создание многомерного массива в языке Си</a><br />В видеоролике объясняется работа с многомерными массивами на примере двумерного.</li><li><a href="https://youtu.be/xUliBLR07Yk">Объявление констант</a><br />В 11-м уроке автор рассказывает о том, что такое константа и как объявить её в коде.</li><li><a href="https://youtu.be/-eUNRbGxGu8">Объявление перечислений в языке Си</a><br />Автор знакомит с ключевым словом enum и рассказывает, как с его помощью создавать собственные типы данных с помощью последовательностей констант.</li><li><a href="https://youtu.be/-_9jP7pLNWM">Отладка с помощью определений препроцессора</a><br />Вы узнаете, какие существуют команды для препроцессора (компонента компилятора, подготавливающего код к компиляции), для чего нужна каждая из них и как применять команды на практике.</li><li><a href="https://youtu.be/8D8IxD70-Fk">Сравнение значений в Си</a><br />В видео рассказывается о сравнении значений переменных с помощью ==, !=, &gt;, &lt;, &gt;=, &lt;=.</li><li><a href="https://youtu.be/RCTeJRPLzIM">Логические значения</a><br />В данном видеоуроке рассматриваются логические операции И &amp;&amp;, ИЛИ || и НЕ !.</li><li><a href="https://youtu.be/P6hyV85Xdvc">Проверка условий — тернарная операция</a><br />Вы познакомитесь с тернарной операцией, которая представляет собой краткую запись if... else, например (a &gt; b) ? a : b.</li><li><a href="https://youtu.be/QE6YQnmY7WA"> Проверка условий if-else</a><br />В 17-м уроке рассматривается конструкция if... else, позволяющая запустить определённый код в зависимости от того, выполнено требуемое условие или нет.</li><li><a href="https://youtu.be/-BNSPHScx5c">Оператор множественного выбора switch case</a><br />В видео рассмотрен оператор switch... case, с помощью которого в зависимости от поданного ключа можно выполнить нужный код.</li><li><a href="https://youtu.be/2AgkNEE1JkY">Цикл for</a><br />Автор рассказывает о цикле for, позволяющем выполнить код внутри цикла при необходимых условиях требуемое количество раз.</li><li><a href="https://youtu.be/UiSGTfXZiQ0">Циклы while, do while</a><br />Цикл while часто используется для перебора элементов и может повторяться сколько угодно раз. Цикл do... while отличается от while блоком do, код в котором вне зависимости от условия выполнится хотя бы один раз.</li><li><a href="https://youtu.be/7ab0dwg62Qw">Утверждения break, continue, goto</a><br />Вы изучите работу с оператором выхода из цикла break, перехода на следующую итерацию цикла continue, а также оператором перехода на определённое место в коде goto.</li><li><a href="https://youtu.be/oCwFTIgEVt4">Функции, прототипы функций</a><br />Здесь даётся введение в функции. Чтобы облегчить понимание, в видео рассматриваются функции без передачи параметров и аргументов. Также вы узнаете, что такое прототип функции.</li><li><a href="https://youtu.be/9MZmHFICaAs">Функции, передача аргументов в функции</a><br />В видеоуроке рассматривается передача аргументов в функции, а также возврат значений из функций.</li><li><a href="https://youtu.be/AHR47U4A9y0">Функции, рекурсия</a><br />В видео рассказывается о рекурсии — вызове функции из самой себя.</li><li><a href="https://youtu.be/mC-gel_YOo0">Сравнение листингов кода на Си</a><br />Вы узнаете, как с помощью команды терминала diff сравнить два файла с исходным кодом.</li><li><a href="https://youtu.be/0YMEGGfhtT4">Пишем код на Си с разделением на файлы</a><br />Вы научитесь разделять свою программу на несколько файлов с исходным кодом и использовать заголовочные файлы с расширением .h.</li><li><a href="https://youtu.be/xQ8lF411K7c"> Указатели в языке Си</a><br />В видеоуроке всё внимание уделяется указателям — переменным, содержащим ссылку на другую переменную.</li><li><a href="https://youtu.be/p6sHWmvwFoM">Передача указателей в функции в языке Си</a><br />С помощью указателей можно напрямую изменять элементы в памяти. Поэтому с их помощью расширяются возможности функций.</li><li><a href="https://youtu.be/gYTgPT7OGOE">Массивы указателей в языке Си</a><br />Тема урока — создание и использование массивов указателей.</li><li><a href="https://youtu.be/aY3hLgypsMs"> Функции ввода и вывода строк в языке Си</a><br />В этом видео автор рассказывает о вводе/выводе строк через терминал с использованием функций printf(), scanf(), fprintf(), fscanf(), gets(), puts(), fgets(), fputs().</li><li><a href="https://youtu.be/7SJipIHydxc">Строки, функции: strcat, strncat в языке Си</a><br />В видеоуроке разбираются функции объединения строк strcat() и strncat().</li><li><a href="https://youtu.be/lSL0pOZuzhE">Строки, функции: strstr, strcmp в языке Си</a><br />Здесь уделяется внимание функции поиска в строке strstr() и функции сравнения строк strcmp().</li><li><a href="https://youtu.be/eoaPut61UE0">Строки, функции: atoi, sprintf, itoa в языке Си</a><br />В видео рассматривается функция перевода из строки в число atoi() и функции перевода из числа в строку sprintf() и itoa().</li><li><a href="https://youtu.be/2YeMTyLTc1o">Структуры в языке Си</a><br />Автор объясняет, что такое структуры, а также как их создавать и объявлять.</li><li><a href="https://youtu.be/wYL_UO3QoEA">Структуры в языке Си: объявление указателей в структуре</a><br />В видеоуроке рассматривается использование указателей в структурах и объясняется, почему в структурах лучше оперировать указателями, чем массивами.</li><li><a href="https://youtu.be/JAc-Dnd4wOA">Структуры в языке Си: указатели на структуры</a><br />Здесь рассказывается о том, что такое указатели на структуры, на что они действительно указывают, а также объясняется, для чего нужен оператор -&gt;.</li><li><a href="https://youtu.be/6I3wA2yQVis">Работа с файлами в языке Си</a><br />В данном видеоуроке рассматривается чтение из файла, запись в файл и создание файла на языке Си. В видео демонстрируются кроссплатформенные методы работы с файлами, однако действия с файлами можно проводить и с помощью системных функций Linux.</li><li><a href="https://youtu.be/51VepdBc57o">Работа с файлами в языке Си: функции fread, fwrite</a><br />Вы познакомитесь с функцией чтения из файла fread() и функцией записи в файл fwrite().</li><li><a href="https://youtu.be/-JFWA1jRU8U">Сообщения об ошибках</a><br />Если при работе с файлами возникают ошибки, их можно обработать с помощью функций perror() и strerror().</li><li><a href="https://youtu.be/aOrzYf48or0">Рандомные числа в Си</a><br />В видео автор разбирает создание псевдослучайных чисел с помощью функций srand(time(NULL)) и rand() и изменение границ множества случайных чисел.</li><li><a href="https://youtu.be/Xzl7EfLOZvQ">Сортировка в Си</a><br />В данном видеоуроке рассматривается использование быстрой сортировки qsort()(Quick Sort), уже встроенной в язык.</li><li><a href="https://youtu.be/kmEhG-0vqgU">WinAPI</a><br />В последнем видео курса вы изучите несколько базовых функций системной библиотеки WinAPI, с помощью которых вы сможете реализовать MessageBox.</li></ol><h3>Дополнительные материалы</h3><p>Чтобы быстро вникнуть в синтаксис языка, вы можете посмотреть часовое видео, в котором объясняются основы языка. В частности, в нём рассказывается о переменных, условных операторах, структурах, типах данных, арифметических операциях, функциях, циклах и многом другом.</p><p>Если видеоуроки не подходят для вас, вы можете ознакомиться с <a href="https://tproger.ru/books/clang-books/">подборкой книг по языку Си</a> и найти для себя подходящую. После изучения основ языка Си вы можете заглянуть в наш <a href="https://tproger.ru/tag/c-language/">раздел</a> с материалами по Си и смежным темам.</p>]]></content:encoded>
    </item>
    <item>
      <title>Эксплуатация уязвимостей исполняемых файлов для новичков: переполнение буфера стека</title>
      <link>https://tproger.ru/translations/binary-exploitation-buffer-overflow</link>
      <comments>https://tproger.ru/translations/binary-exploitation-buffer-overflow?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Никита Прияцелюк]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/binary-exploitation-buffer-overflow</guid>
      <description><![CDATA[<p>Материал для неподготовленных читателей объясняет атаку переполнения буфера стека, работу памяти приложений и концепцию виртуальной памяти.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/binary-exploitation-buffer-overflow">Эксплуатация уязвимостей исполняемых файлов для новичков: переполнение буфера стека</a>»</p>]]></description>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 08 Jan 2019 15:06:09 GMT</pubDate>
      <content:encoded><![CDATA[<p>В этой статье будет рассмотрена атака переполнения буфера стека, с подробным описанием того, что это такое, как это работает и какие технологии используются для её реализации. Статья написана так, чтобы тему смог понять мог даже неподготовленный читатель.</p><h2>Теория: память приложений</h2><p>При выполнении приложения загружаются в память. Но как мы все знаем, компьютеры имеют ограниченное количество памяти, и приложению нужно быть очень осторожным, чтобы не перезаписать область в памяти, принадлежащую другому приложению. Для того, чтобы избежать такой ситуации, используется так называемая виртуальная память, которую можно прекрасно описать с помощью сцены из сериала, выпущенного в начале 2000-х — <a href="https://ru.wikipedia.org/wiki/Дрейк_и_Джош">Дрейк и Джош</a>, в котором главные герои раскладывают суши по контейнерам:</p><p>В этой сцене Дрейк и Джош получили работу, в которой суши идут по конвейеру, и их нужно разложить по контейнерам. Более того, несмотря на то, что контейнеры выглядят одинаково, в одном контейнере должен быть только один тип суши.</p><p>Прим. перев. Посмотреть серию можно здесь, сцена с суши на 18 минуте.</p><p>Давайте перейдём от аналогии к концепции виртуальной памяти.</p><p>Конвейер с суши: как уже говорилось ранее, компьютеры имеют ограниченную память и должны быть очень осторожны и точны при записи данных, чтобы не перезаписать память других приложений. Хоть компьютер и может просто записать приложение в физическую память, в конечном итоге это приведёт к проблемам, так как фрагменты приложений быстро заполнят всю свободную память. В примере выше индивидуальные сушинки можно рассматривать как фрагменты приложения или часть памяти, занятой определённым приложением, а набор суши из шести штук — само приложение.</p><p>Дрейк и Джош: чтобы обойти проблему с заполнением конвейера одиночными сушинками, главные герои разбирают их по разным контейнерам, которые потом отправляют дальше по конвейеру. Ваш компьютер, как Дрейк и Джош, распределяет приложения по контейнерам, называемым виртуальным адресным пространством. Такие виртуальные адресные пространства позволяют приложению считать, что оно имеет полный контроль над всей памятью устройства. Однако когда приложение пытается получить доступ к памяти вне своего виртуального адресного пространства, маленькая, но чрезвычайно важная часть вашего ЦПУ — блок управления памятью — перенаправляет обращение к физической памяти в соответствии с выделенной областью для этого приложения, облегчая таким образом любую работу с памятью. Такое распределение позволяет компьютеру организовать работу сразу нескольких приложений через справочную таблицу с требованиями в виде динамической памяти.</p><p><a href="https://media.tproger.ru/uploads/2019/01/image3.jpg"></a> ASCII-диаграмма работы виртуальной памяти</p><p>Также важно знать, что код всех приложений содержится внутри их виртуального адресного пространства. Приложения часто используют динамически подключаемые библиотеки (DLL), такие как libc или kernel32. DLL — внешние (т. е. не хранятся в исполняемом файле запускаемого приложения) системные или специально написанные библиотеки, которыми пользуется приложение. Пример представлен ниже.</p><p>Как вы видите, нигде в этой шестистрочной программе не объявляется printf(). Однако эта программа всё равно запустится без ошибок и выведет «Hello World». Это потому, что функция printf() — системная функция, определённая в libc, стандартной библиотеке C. Во время компиляции libc внешне подключается к исполняемому файлу. В системах Linux можно посмотреть используемые программой библиотеки с помощью команды ldd.</p><p><a href="https://media.tproger.ru/uploads/2019/01/lib-dep.jpeg"></a> Отображение используемых программой библиотек с помощью ldd</p><p>Если вы смотрите на скриншот выше и думаете, что такое 0xb7e99000, то это адрес библиотеки libc в памяти. Адреса в памяти представлены в шестнадцатеричном формате. Более подробно о шестнадцатеричном формате вы можете узнать <a href="https://inf1.info/hexadecimal">здесь</a>.</p><h2>Теория: стек</h2><p>Стек — это просто большая структура данных, которая используется для хранения приложением информации или данных во время её работы. Работу стека можно описать следующей аналогией:</p><p>Боб — мойщик посуды в модном ресторане. Каждый вечер у Боба есть стопка тарелок, которые нужно вымыть. Более того, в течение ночи на верх стопки могут добавляться ещё тарелки, по мере уборки столов. Если Боб возьмёт тарелку откуда-то ещё кроме как сверху стопки, то вся стопка развалится и тарелки разобьются.</p><p>А теперь вместо Боба и стопки тарелок представьте компьютер и стопку объектов с данными. Когда что-то добавляется (push) в стек, оно кладётся наверх стопки. Когда извлекается (pull), то берётся сверху стопки. Так работает механизм LIFO (Last In First Out, последним пришёл — первым вышел).</p><p>Стек используется программами для хранения различных вещей, например, указателей на функции и переменных.</p><h2>Теория: вызов функций и возвраты</h2><p>Посмотрите на код, представленный ниже:</p><p>В этом фрагменте кода мы видим что функция add() принимает два аргумента целочисленного типа, имена которых А и В. В функции main() мы вызываем функцию add() с 1 в качестве аргумента А и 2 — В. Если перевести это в машинный код:</p><p>Как вы видите, при вызове функции с параметрами программа сначала добавляет оба параметра в стек, а затем выполняет команду call. Команда call перенаправляет указатель инструкции программы по адресу вызываемой функции. Указатель программы подобен маленькому карандашу, который вы используете для отслеживания слов при чтении. Указатель инструкции всегда указывает на ту инструкцию, которая должна быть выполнена (слово, которое будет прочитано). Однако, перед тем, как перейти к вызываемой функции, команда call помещает адрес следующей за ним инструкции в стек, чтобы, когда произойдёт возврат из функции add(), было известно, с чего продолжать выполнение программы. Адрес места, в которое функция должна вернуться, называется указателем возврата функции.</p><h2>Атака: переполнение буфера стека</h2><p>Прежде чем углубляться в технические подробности о том, что такое переполнение стекового буфера и как оно работает, давайте рассмотрим простую для понимания аналогию:</p><p>Алиса и Боб раньше встречались, но в итоге Алиса рассталась с Бобом. Время шло, Алиса оставила прошлое позади, но Бобу так и не удалось справиться с горем. Теперь Алиса выходит замуж за Роберта Хакермана, заклятого врага Боба. Боб, будучи жутким чудаком, следил за всеми свадебными планами Алисы благодаря своему секретному доступу к электронной почте Алисы. Боб увидел, что Алиса наняла известного дизайнера свадебных тортов, который хотел, чтобы Алиса отредактировала части своего рецепта под свои вкусовые предпочтения. Дизайнер дал Алисе рекомендованный список ингредиентов, которые можно добавить, но сказал, что сделает всё в точности, как она захочет. Боб открыл документ, прикреплённый к электронному письму дизайнера, и увидел, что меняемые строки рецепта выглядят так:<em>... Затем мы наделим глазурь вкусом, добавив _____. После этого мы добавим немного шоколада ...</em>Боб заметил, что если ввести «банан» в строку, текст будет выглядеть так:<em>... Затем мы наделим глазурь вкусом, добавив банан. После этого мы добавим немного шоколада ...</em>Но если Боб введёт «клубника» в строку, текст будет выглядеть так:<em>... Затем мы наделим глазурь вкусом, добавив клубникуосле этого мы добавим немного шоколада ...</em>Боб понял, что это будет идеальный способ испортить свадьбу Алисы, и всё, что ему нужно было сделать, это переписать остальную часть рецепта своей собственной отвратительной версией! В день свадьбы Алисы дизайнер наконец-то показал торт, который он сделал — он был покрыт жуками и сделан из замороженного майонеза!</p><p>Переполнение буфера стека, как и атака Боба, перезаписывает данные, которые разработчик не собирался перезаписывать, обеспечивая полный контроль над программой и её выходными данными.</p><p>Итак, теперь давайте посмотрим на это в реальном мире. Взгляните на следующий фрагмент кода:</p><p>В приведённой выше функции мы видим, что массив символьного типа с именем buffer создаётся с размером 64. Затем мы видим, что переменная modified равна 0, и функция gets() вызывается с переменной buffer в качестве аргумента. Наконец, мы видим оператор IF, который проверяет, не равно ли значение modified нулю. Очевидно, что нет, где в этом приложении переменная modified имеет значение, отличное от 0. Так как мы собираемся её изменить?</p><p>Что ж, давайте сначала посмотрим на документацию функции gets():</p><p><a href="https://media.tproger.ru/uploads/2019/01/gets-docs.jpeg"></a> Определение функции gets()</p><p><a href="https://media.tproger.ru/uploads/2019/01/gets-bugs.jpeg"></a> Описание багов в функции gets()</p><p>Как видите, функция gets() просто принимает пользовательский ввод. Однако функция не проверяет, действительно ли пользовательский ввод вписывается в структуру данных, в которой мы его храним (в данном случае это buffer), и, таким образом, мы можем переполнить структуру данных и повлиять на другие переменные и данные стека. Кроме того, поскольку мы знаем, что все переменные хранятся в стеке, и мы знаем, что представляет собой переменная modified (0), всё, что нам нужно сделать, — это ввести достаточно данных, чтобы перезаписать переменную modified. Давайте посмотрим на диаграмму:</p><p><a href="https://media.tproger.ru/uploads/2019/01/image9.jpg"></a> ASCII-диаграмма переполнения буфера стека</p><p>Как видите, если злоумышленник просто вводит слишком много текста, он может перезаписать переменную modified и всё остальное в стеке, включая указатели возврата. Это означает, что если злоумышленник сможет взять под контроль стек программы, он сможет эффективно контролировать всю программу и заставить её делать то, что он хочет. Например, можно просто перезаписать указатель возврата функции в стеке на пользовательский, указывающий на вредоносную функцию.</p><h2>Атака: ret2libc</h2><p>Как мы знаем из первого раздела, libc — это стандартная библиотека языка C. Это означает, что она содержит все общие системные функции, включённые в язык программирования C. Теперь, что если злоумышленник сможет взять под контроль программу для выполнения некоторых из этих функций?</p><p>Это и есть ret2libc. Одной идеальной аналогией для последствий ret2libc может быть серия <a href="https://www.imdb.com/title/tt0133093/">Матрицы</a>. Вспомните классическую сцену <a href="https://www.youtube.com/watch?v=iOcFB0ourBo">«Оружие, много оружия»</a>. Оператор Танк смог полностью обойти и перепрограммировать матрицу, чтобы МОРЕ оружия просто появилось из ниоткуда.</p><p>Вы можете думать о возврате в libc вот так: мы можем взять под контроль матрицу (стандартную библиотеку C) и заставить её делать то, что мы хотим.</p><p>По сути, атаки ret2libc фактически основаны на переполнении стекового буфера. Вспомните, что было сказано в конце предыдущего раздела: если злоумышленник может перезаписывать данные в стеке, он может просто перезаписать указатель возврата, чтобы указать на конкретную функцию в libc, и передать ей любые аргументы, необходимые для доставки полезной нагрузки.</p><p>Одной из самых распространённых функций для атак ret2libc является функция system(). Давайте посмотрим на документацию:</p><p><a href="https://media.tproger.ru/uploads/2019/01/sys-docs.jpeg"></a> Документация по функции system()</p><p>Как видите, функция system() просто выполняет shell-команды (shell — это командная строка Linux). Более того, если мы прочитаем описание, то увидим, что система просто выполняет /bin/sh -c &lt;команда&gt;, и команда передаётся в функцию через аргумент.</p><p>Итак, всё, что нам нужно сделать, чтобы получить доступ из командной строки к компьютеру, на котором запущено уязвимое приложение, — это вставить «/bin/sh» в стек в качестве аргумента, а затем заменить указатель возврата или вызова адресом памяти функции system(), так чтобы эта функция вызывалась с /bin/sh в качестве аргумента, запускала оболочку и предоставляла нам полный доступ через систему.</p><p>Как видите, эксплуатация даже такой, казалось бы простой уязвимости, может привести к катастрофическим последствиям для машины, где находится уязвимый файл. В <a href="https://tproger.ru/translations/stack-protection-bypass/">следующем материале</a> будут описаны другие уязвимости и способы защиты от них.</p>]]></content:encoded>
    </item>
    <item>
      <title>Для IDE CLion вышло обновление 2018.2</title>
      <link>https://tproger.ru/news/clion-2018-2</link>
      <comments>https://tproger.ru/news/clion-2018-2?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Тимур Кондратьев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/clion-2018-2</guid>
      <description><![CDATA[<p>В CLion 2018.2 добавили экспериментальный языковой движок на базе clangd, новые проектные модели и важные исправления производительности.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/clion-2018-2">Для IDE CLion вышло обновление 2018.2</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[JetBrains]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 26 Jul 2018 07:34:50 GMT</pubDate>
      <content:encoded><![CDATA[<p>JetBrains <a href="https://blog.jetbrains.com/clion/2018/07/clion-2018-2-clangd-gradle-compdb-sanitizers/">выпустила</a> крупное обновление для интегрированной среды разработки CLion под номером 2018.2. Новая версия принесла дополнительный экспериментальный языковой движок на базе clangd, новые проектные модели, а также несколько важных исправлений производительности.</p><h3>С++</h3><p>Разработчики добавили в IDE поддержку экспериментального языкового движка, основанного на clangd, в дополнение к основному. Он включен по умолчанию на macOS и Linux, а в Windows-версии его необходимо активировать вручную в настройках. Экспериментальная функция используется только для показа ошибок и предупреждений в редакторе, а настроить их под себя можно в окне Clangd:</p><figure><img src="https://media.tproger.ru/uploads/2018/07/clangd_settings.png" alt="" /></figure><p><a href="https://blog.jetbrains.com/clion/2018/06/clion-2018-2-eap-clangd/">Разобраться</a> с тем, как работает новый движок, можно в блоге компании.</p><p>Кроме того, в обновлении появилось обновленное инспектирование кода, которое определяет аргументы одного типа, идущие в неправильном порядке. Оно требует выразительных имен параметров, а также включенного экспериментального движка. Инспектирование полагается на несколько эвристических алгоритмов.</p><figure><img src="https://media.tproger.ru/uploads/2018/07/wrong_arguments_inspection.png" alt="" /></figure><h3>Новые проектные модели</h3><p>Ранее, утверждают разработчики, написанные не с использованием CMake проекты получали ограниченную функциональность CLion. Теперь IDE полностью поддерживает как проекты на <a href="https://blog.jetbrains.com/clion/2018/05/clion-starts-2018-2-eap-sanitizers-gradle-db-performance/#gradle_cpp_projects">Gradle C++</a>, так и <a href="https://blog.jetbrains.com/clion/2018/05/clion-2018-2-eap-open-project-from-compilation-database/">базы данных компиляции</a>. Чтобы открыть проект, необходимо:</p><ul><li>открыть файл build.gradle из исходников проекта, написанного с использованием <a href="https://blog.gradle.org/introducing-the-new-cpp-plugins">новых плагинов Gradle C++</a>;</li><li>использовать файл compile_commands.json из базы данных компиляции.</li></ul><p>Также они не забыли и про CMake. Обновление принесло возможность не записывать заголовочные файлы напрямую, чтобы довольствоваться всеми возможностями понимания кода. Если добавить заголовочный или исходный файл в любой проект, среда разработки автоматически сделает его файлом проекта:</p><figure><img src="https://media.tproger.ru/uploads/2018/07/project_files.gif" alt="" /></figure><h3>Новые инструменты</h3><p>Улучшение получил динамический анализатор кода Valgrind Memcheck, добавленный в 2017.3. Создатели IDE сделали возможным импорт/экспорт результатов анализа из CLion.</p><p>В дополнение к Valgrind среда разработки получила поддержку <a href="https://github.com/google/sanitizers">Google Sanitizers</a>. Для их включения требуется флаг сборки -fsanitize, который нужно ввести вручную. CLion с Clang версии выше 3.8.0 и GCC выше 5.0.0 затем автоматически распознает флаг и покажет результаты анализа Google Sanitizers в отдельной вкладке:</p><figure><img src="https://media.tproger.ru/uploads/2018/07/sanitizers.gif" alt="" /></figure><p>С полным списком поддерживаемых Sanitizers и их настройками <a href="https://blog.jetbrains.com/clion/2018/05/clion-starts-2018-2-eap-sanitizers-gradle-db-performance/#google_sanitizers">можно ознакомиться</a> в блоге JetBrains.</p><p>Более того, разработчики послушали пользователей Твиттера и включили полную поддержку инструментов баз данных и SQL в виде плагина. Среди поддерживаемых БД есть такие, как MySQL, PostgreSQL, Oracle, DB2 и Sybase.</p><h3>Отладчик</h3><p>CLion 2018.2 «из коробки» поддерживает такие инструменты отладки, как LLDB 6.0 на macOS и Linux, а также GDB 8.1 на Linux и Windows и GDB 8.0.1 — на macOS.</p><p>Теперь IDE использует «украшатели» типа для отображения указателей этого типа при работе с GDB, а LLDB правильно обрабатывает unsigned char и unordered_map.</p><h3>Другие улучшения</h3><p>Clion 2018.2 также получила множество мелких улучшений и обновлений, среди которых <a href="https://blog.jetbrains.com/clion/2018/05/clion-starts-2018-2-eap-sanitizers-gradle-db-performance/#recompile_single_file">перекомпиляция</a> единственного файла для ускорения процессов разработки, поддержка Touch Bar новых MacBook, а также создание процессора, запускающего форматирование только лексем языка для улучшения работы интерфейса, и многое другое. По традиции разработчики из JetBrains опубликовали видеоролик, рассказывающий об обновлении:</p><p>Подробнее обо всех улучшениях и исправлениях <a href="https://www.jetbrains.com/clion/whatsnew/">можно узнать</a> на официальной странице обновления.</p><p>Предыдущая крупная версия IDE под номером 2018.1 <a href="https://tproger.ru/news/clion-2018-1/">вышла</a> в марте 2018 года. В нее была добавлена поддержка WSL и CMake Install.</p>]]></content:encoded>
    </item>
    <item>
      <title>JetBrains выпустила обновление 2018.1 для CLion</title>
      <link>https://tproger.ru/news/clion-2018-1</link>
      <comments>https://tproger.ru/news/clion-2018-1?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дмитрий Сироткин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/clion-2018-1</guid>
      <description><![CDATA[<p>Обновление CLion 2018.1 улучшает разработку на C/C++ в Windows и добавляет поддержку WSL, CMake Install и настройки проверок Clang-Tidy.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/clion-2018-1">JetBrains выпустила обновление 2018.1 для CLion</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[JetBrains]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 31 Mar 2018 17:10:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>Компания JetBrains <a href="https://blog.jetbrains.com/clion/2018/03/clion-2018-1-cpp17-wsl-cmake-install/">представила</a> первое в 2018 году крупное обновление интегрированной среды разработки CLion. Выпущено множество улучшений для разработки на C/С++ на всех платформах, в особенности на Windows. Также обновления коснулись языков Objective-C, Objective-C++, Rust и Fortran.</p><h3>C++17</h3><p>Компания экспериментирует с альтернативами для языкового движка CLion и планирует выпустить первые результаты в последующих версиях в 2018 году. Тем не менее, в настоящее время последние улучшения коснулись текущей версии:</p><ul><li>поддержка декомпозиции при объявлении (структурированные привязки);</li><li>инициализаторы if и switch стандарта C++17;</li><li>полноценная поддержка тернарного оператора;</li><li>переработаны рефакторинги Rename и Change Signature для случая наследования:</li></ul><figure><img src="https://media.tproger.ru/uploads/2018/03/CLion_2018.1_rename_refactoring.gif" alt="" /></figure><p>Редактор в целом стал более отзывчивым благодаря существенным изменениям обработчиков ввода и инкрементальной подсветке.</p><h3>Clang-Tidy</h3><p>Мощный инструмент, дополняющий собственный анализатор CLion. Разработчики добавили возможности увеличения его влияния. Теперь можно прописывать опции для некоторых проверок, например, modernize-use-nullptr. Также появилась возможность указать .clang-tidy в качестве файла конфигурации CLion вместо стандартного. Это означает, что вся команда может теперь использовать единый набор правил Clang-Tidy независимо от пользовательских настроек IDE и редакторов.</p><figure><img src="https://media.tproger.ru/uploads/2018/03/Clang_Tidy_settings.png" alt="" /></figure><p>Помимо этого <a href="https://confluence.jetbrains.com/display/CLION/Clang-Tidy+in+CLion%3A+default+configuration">обновлен</a> и оптимизирован набор проверок Clang-Tidy по умолчанию.</p><h3>WSL</h3><p>Поддержка компилятора Microsoft Visual C++ теперь включена по умолчанию. Также расширен набор инструментов на Windows за счет поддержки слоя <a href="https://ru.wikipedia.org/wiki/Windows_Subsystem_for_Linux">WSL</a>, позволяющего компилировать, запускать и отлаживать исполняемые файлы сборок Linux. CLion будет использовать компиляторы CMake, make, GCC/G++ и отладчик WSL для сборки и запуска.</p><figure><img src="https://media.tproger.ru/uploads/2018/03/WSL_toolchain_settings.png" alt="" /></figure><p>Поддержка WSL содержит <a href="https://tproger.ru/news/clion-2017-3/">выпущенный</a> ранее анализатор кода <a href="http://valgrind.org/docs/manual/mc-manual.html">Valgrind Memcheck</a> для выявления ошибок, связанных с памятью:</p><figure><img src="https://media.tproger.ru/uploads/2018/03/WSL_Valgrind_set.png" alt="" /></figure><p>Руководство по установке и конфигурации WSL <a href="https://blog.jetbrains.com/clion/2018/01/clion-and-linux-toolchain-on-windows-are-now-friends/">доступно</a> для ознакомления в блоге компании.</p><p>По словам разработчиков, WSL является первым шагом к поддержке удаленного доступа в CLion, поэтому в его реализации использован SSH.</p><h3>CMake</h3><p>Начат процесс отсоединения проектной модели CMake от CLion. Для случая, когда нужно просто прочитать сторонний код на C++ в CLion, появилась возможность открывать один файл или каталог без задействования CMake. Тем не менее, CLion все еще нуждается в модели CMake для предоставления умных фич IDE. Интеграция самой CMake продолжается, в связи с чем в редакторе появилось действие CMake Install во вкладке Run, доступное также для добавления в качестве шага в конфигурации запуска:</p><figure><img src="https://media.tproger.ru/uploads/2018/03/clion_cmake_install.png" alt="" /></figure><p>Командой Create new file (Alt+Insert) можно создать файл CMakeLists.txt, содержимое которого определяется шаблоном в настройках редактора.</p><h3>Редактор</h3><p>Команда разработчиков время от времени использует CLion в собственных нуждах, что позволяет ощущать необходимость некоторых косметических улучшений:</p><ul><li>«Сухарики» («breadcrumbs») для C/C++  — маленькие маркеры в нижней части редактора, облегчающие навигацию по коду, отображая текущие пространства имен, классы, структуры, функции и лямбда-выражения:<br /><a href="https://media.tproger.ru/uploads/2018/03/clion_breadcrumbs.png"></a></li></ul><ul><li>Удаление конструкций — безопасное удаление if, else, for, while, do..while и for, а также удаление частей вложенных операторов:<br /><a href="https://media.tproger.ru/uploads/2018/03/clion_unwrap_ternary.gif"></a></li></ul><ul><li>Свертка управляющих операторов — одна из самых востребованных функций. Сочетанием Shift+Ctrl+Period / Ctrl+= (Windows / Linux) или ⇧⌘. / ⌘+ (macOS) можно сворачивать тела if / else, do / while, for и switch), а также операторы целиком.</li><li>Настройки окна сообщений — дополнительные опции позволяют задать тип выводимых сообщений в логе.</li></ul><p>Также стоит упомянуть Project Scopes — возможность изучить проект с разных углов, используя как предопределенные режимы Project Source Files, Project Non-Source Files и Changed files, так и задавая свои режимы просмотра.</p><h3>VCS</h3><p>В интерфейсе CLion появились частичные коммиты (git add -p), позволяют зафиксировать лишь часть изменений проекта. Выделив участки кода для коммита, нужно снять соответствующие галочки в диалоговом окне. Также доступна возможность перемещать изменения между списками прямо из редактора.</p><figure><img src="https://media.tproger.ru/uploads/2018/03/clion_changelists.png" alt="" /></figure><p>Больше информации об этой функциональности <a href="https://blog.jetbrains.com/idea/2018/02/intellij-idea-2018-1-eap-partial-git-commits-and-more/">доступно</a> в блоге компании.</p><h3>Rust, Fortran и Objective-C/C++</h3><p>CLion 2018.1 <a href="https://blog.jetbrains.com/clion/2018/01/clion-starts-2018-1-eap-wsl-cpp17-cmake/#objc">включает</a> поддержку Objective-C and Objective-C++. Также стали доступны обновленные плагины для Rust и Fortran. Плагин Rust содержит отладчик и менеджер пакетов Cargo, добавленный благодаря отсоединению проектной модели CMake. Плагин Fortran работает посредством CMake и поддерживает FORTRAN 77, Fortran 90, Fortran 95, Fortran 2003 и Fortran 2008. Подробнее о плагинах можно <a href="https://blog.jetbrains.com/clion/2018/03/from-cpp-to-native-development-rust-and-fortran-plugins-in-clion/">прочитать</a> в блоге JetBrains.</p><p>С другими изменениями можно ознакомиться в традиционном кратком видео-обзоре:</p><p>Более подробный список нововведений <a href="https://www.jetbrains.com/clion/whatsnew/">доступен</a> на официальной странице обновления.</p>]]></content:encoded>
    </item>
    <item>
      <title>Фичи Rust, которых не хватает в C</title>
      <link>https://tproger.ru/translations/rust-things-i-miss-in-c</link>
      <comments>https://tproger.ru/translations/rust-things-i-miss-in-c?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[levon ward]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/rust-things-i-miss-in-c</guid>
      <description><![CDATA[<p>Федерико Мена-Кинтеро, один из основателей GNOME, называет C примитивным языком для современного ПО и отмечает его недостатки относительно Rust.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/rust-things-i-miss-in-c">Фичи Rust, которых не хватает в C</a>»</p>]]></description>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 28 Feb 2018 19:39:17 GMT</pubDate>
      <content:encoded><![CDATA[<p>Перевод статьи Федерико Мена-Кинтеро, который, наряду с Мигелем де Икаса, основал <a href="https://www.gnome.org/">проект GNOME</a> — широко используемую, свободную графическую среду, в основном для систем GNU/Linux. Перед этим он некоторое время поддерживал <a href="https://www.gimp.org/">GIMP</a>. Сейчас Федерико активно развивает библиотеку librsvg с использованием языка программирования Rust. По его мнению, разработка достигла момента, когда портирование некоторых крупных компонент с C на Rust выглядит более лёгкой задачей, чем просто добавление аксессоров к ним. Федерико часто приходится переключаться с C на Rust и обратно, и в статье он рассказывает, почему считает C очень и очень примитивным языком для современного ПО.</p><h2>Своего рода элегия по C</h2><p>Я влюбился в язык программирования C около 24-ёх лет назад. Я выучил основы, прочитав испанский перевод второго издания <a href="https://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%A1%D0%B8_(%D0%BA%D0%BD%D0%B8%D0%B3%D0%B0)">«Языка программирования C» Кернигана/Ритчи (K&amp;R)</a>. До этого я писал на Turbo Pascal в довольно низкоуровневой манере — с указателями и ручным выделением памяти. После него C казался освежающим и мощным.</p><p>К&amp;R — это отличная книга благодаря стилю изложения и лаконичности программирования. Эта книга даже учит, как реализовать простые функции malloc/free, что крайне поучительно. Даже такие низкоуровневые конструкции, которые выглядят как часть языка, могут быть реализованы на самом языке!</p><p>В последующие годы я хорошо освоил C. Это простой язык с небольшой стандартной библиотекой. Наверное, это был идеальный язык для реализации ядер Unix в 20 000 строк кода или около того.</p><p>GIMP и GTK+ научили меня тому, как использовать модный объектно-ориентированный подход в C. GNOME показал, как поддерживать крупномасштабные проекты, написанные на C. Стало казаться, что 20 000 строк C кода — это проект, который можно практически полностью понять за пару недель.</p><p>Но наши кодовые базы уже далеко не такие маленькие. Сейчас в процессе разработки программного обеспечения огромные надежды возлагаются на функции, доступные в стандартной библиотеке языка.</p><h2>Опыт использования C</h2><h3>Положительный</h3><ul><li>Чтение исходного кода проекта POV-Ray впервые и изучение того, как использовать объектно-ориентированный подход и наследование в чистом C;</li><li>Чтение исходного кода проекта GTK+ и изучение читаемого, поддерживаемого и чистого стиля написания кода на C;</li><li>Чтение исходного кода проекта SIOD, а также ранних исходников проекта Guile и понимание того, как интерпретатор Scheme может быть написан на C;</li><li>Написание первых версий Eye of Gnome и доработка системы микротайлового рендеринга.</li></ul><h3>Негативный</h3><ul><li>Работа в команде Evolution, когда программа постоянно падала. Мы были вынуждены приобрести машину с Solaris на борту, чтобы иметь возможность купить Purify; в те времена Valgrind-а еще не существовало;</li><li>Отладка взаимных блокировок потоков в gnome-vfs;</li><li>Безуспешная отладка Mesa;</li><li>Когда мне передали исходники первых версий Nautilus-share, я увидел, что free() вообще не используется;</li><li>Попытки рефакторинга кода, о стратегии управления памятью которого я не имел понятия;</li><li>Попытка сделать библиотеку из кода, кишащего глобальными переменными, и в котором ни одна функция не помечена как static.</li></ul><h2>Фичи Rust, которых не хватает в C</h2><h3>Автоматическое управление ресурсами</h3><p>Один из первых блог-постов, которые я прочитал о Rust, назывался <a href="http://blog.skylight.io/rust-means-never-having-to-close-a-socket/">«В Rust вам никогда не придётся закрывать сокет»</a>. Rust заимствует у C++ идеи об идиоме <a href="https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization">RAII</a> (Resource Acquisition Is Initialization, получение ресурса есть инициализация) и умных указателях, добавляет принцип единоличного владения для значений и предоставляет механизм автоматического, детерминированного управления ресурсами в очень изящной упаковке.</p><ul><li>Автоматическое: не нужно вызывать free() вручную. Память освободится, файлы закроются, мьютексы разблокируются, когда переменные выйдут из зоны видимости. Если вам нужно написать обёртку для стороннего ресурса, то всё, что нужно сделать, это реализовать типаж Drop. Обёрнутый ресурс ощущается как часть языка, потому что вам не приходится нянчиться с его временем жизни вручную;</li><li>Детерминированное: ресурсы создаются (память выделяется и инициализируется, файлы открываются и т. д.) и уничтожаются, когда выходят из зоны видимости. Никакой сборки мусора: ресурсы действительно освобождаются, когда вы закрываете скобку. Вы начинаете видеть время жизни данных в своей программе как дерево вызовов функций.</li></ul><p>После того, как постоянно забываешь освобождать/закрывать/уничтожать объекты в C, или, ещё хуже, пытаешься понять, где в чужом коде забыли сделать что-то из этого (или ошибочно сделали дважды)… я просто больше этого не хочу.</p><h3>Дженерики</h3><p>Vec&lt;T&gt; — это действительно вектор, размер элементов которого равен размеру объекта типа T. Это не массив указателей на объекты, память для которых выделялась отдельно. Он специально компилируется в код, который может работать только с объектами типа T.</p><p>После написания большого количества сомнительных макросов на C, чтобы сделать что-то похожее… я больше этого не хочу.</p><h3>Типажи — это больше, чем просто интерфейсы</h3><p>Rust — это не Java-подобный объектно-ориентированный язык, подробнее об этом можно прочитать в open-source книге <a href="https://doc.rust-lang.org/book/second-edition/ch17-00-oop.html">«The Rust Programming Language»</a>. Вместо этого в нём есть типажи, которые поначалу похожи на интерфейсы в Java, — простой способ осуществления динамического переключения (dynamic dispatch), так что если объект реализует Drawable, то можно предположить, что у него есть метод draw().</p><p>Однако типажи — это более мощный инструмент. Одной из отличительных особенностей типажей можно считать ассоциированные типы (<a href="https://doc.rust-lang.org/book/second-edition/ch19-03-advanced-traits.html">associated types</a>). Например, Rust предоставляет типаж Iterator, который вы можете реализовать:</p><p>Это означает, что всякий раз, когда вы реализуете этот типаж для какого-либо объекта, поддерживающего итерирование, вы также указываете тип Item для значений, которые он выдаёт. Если вы вызываете next() и элементы ещё остались, вы получите Some(ТипВашегоЭлемента). Когда у вашего итератора закончатся элементы, он вернет None.</p><p>Ассоциированные типы могут ссылаться на другие типажи.</p><p>Например, в Rust вы можете использовать циклы for со всем, что реализует типаж IntoIterator:</p><p>Когда реализуете этот типаж, вы должны указать и тип элементов, которые будет выдавать ваш итератор, и сам тип IntoIter, который реализует типаж Iterator и хранит состояние вашего итератора.</p><p>Таким образом, вы можете построить настоящую сеть типов, которые ссылаются друг на друга. Вы можете написать типаж, который говорит: «Я могу сделать foo и bar, но только если вы дадите мне тип, который умеет делать вот это и это».</p><h3>Срезы</h3><p>Я уже писал о том, насколько в C не хватает срезов (slices) для работы со строками и какая это головная боль, когда привык, что они под рукой.</p><h3>Современные инструменты для управления зависимостями</h3><p>Вместо того, чтобы</p><ul><li>Запускать pkg-config руками или через Autotools-макрос;</li><li>Сражаться с include-путями в заголовочных файлах…</li><li>… и библиотечных файлах;</li><li>И, по сути, полагаться на то, что пользователь гарантирует установку верных версий библиотек,</li></ul><p>вы пишете файл Cargo.toml, в котором перечисляются названия и версии всех наших зависимостей. Они будут загружены из общеизвестного источника или из любого другого, указанного вами.</p><p>Не нужно сражаться с зависимостями. Оно просто работает, когда вы набираете cargo build.</p><h3>Тесты</h3><p>В C очень сложно покрывать код тестами по нескольким причинам:</p><ul><li>Внутренние функции часто помечены как static. Это означает, что они не могут быть вызваны вне файла, в котором эта функция определена. Тестовая программа вынуждена либо #include-ить содержимое исходника, в котором функция объявлена, либо использовать #ifdef, чтобы убирать static только при тестировании;</li><li>Вам придётся плясать с бубном вокруг вашего Makefile, чтобы слинковать тестовую программу с определённой частью зависимостей основной или с какой-то частью оставшейся программы;</li><li>Вам придётся выбрать фреймворк для тестирования. Вам придётся зарегистрировать свои тесты в фреймворке для тестирования. Вам придётся изучить этот фреймворк.</li></ul><p>В Rust вы пишете</p><p>в любом месте программы или библиотеки, и, когда вы набираете cargo test, ОНО ПРОСТО, *****, РАБОТАЕТ. Этот код линкуется только в тестовый исполняемый файл. Не нужно ничего компилировать дважды вручную, писать Makefile-магию или разбираться, как вытащить внутренние функции для тестирования.</p><p>Для меня это одна из главных киллер-фич языка.</p><h3>Документация с тестами</h3><p>Rust генерирует документацию на основе комментариев, размеченных с помощью Markdown. Код из документации запускается как обычные тесты. Вы можете показывать, как функция должна использоваться, одновременно тестируя её:</p><p>Код из примера запускается как тест, чтобы убедиться, что ваша документация своевременно обновляется вместе с кодом программы.</p><h3>Гигиеничные макросы</h3><p>В Rust особые гигиеничные макросы, позволяющие избежать проблем, при которых во время разворачивания C макросов происходит непреднамеренное затенение идентификаторов в коде. Вам больше не нужно писать макросы, заключая все символы в скобки, чтобы max(5 + 3, 4) работал правильно.</p><h3>Никакого неявного приведения типов</h3><p>Все эти баги, которые появляются в C из-за непреднамеренного приведения int к short или к char и т. п. — в Rust их нет. Вы должны приводить типы явно.</p><h3>Никакого целочисленного переполнения</h3><p>Этим всё сказано.</p><h3>Как правило, никакого неопределённого поведения в безопасном режиме</h3><p>В Rust, если что-то вызывает неопределенное поведение в «безопасном режиме» (всё, что написано вне блоков unsafe {}), это расценивается как баг самого языка. Например, можно сделать побитовый сдвиг отрицательного целого числа вправо и произойдёт именно то, что вы ожидаете.</p><h3>Сопоставление с образцом</h3><p>Знаете, как gcc выдает предупреждение, если вы используете switch() с перечислением (enum), но обработаете не все варианты? Это детский сад по сравнению с Rust.</p><p>В Rust в различных местах используется <a href="https://doc.rust-lang.org/book/second-edition/ch18-03-pattern-syntax.html">сопоставление с образцом</a>. Он умеет делать эту штуку с перечислениями в match-выражении. Он поддерживает деструктурирование, а это значит, что можно возвращать несколько значений из функции:</p><p>match работает на строках. ВЫ МОЖЕТЕ МАТЧИТЬ ГРЁБАНЫЕ СТРОКИ.</p><p>Вы же знаете, насколько такое плохо читается?</p><p>my_func(true, false, false)</p><p>Как насчет того, чтобы вместо этого использовать сопоставление с образцом на аргументах функции:</p><h3>Стандартная полезная обработка ошибок</h3><p>Я подробно останавливался на этом. Больше никаких булевых возвращаемых значений без нормального описания ошибки, никаких случайно проигнорированных ошибок, никакой обработки исключительных ситуаций longjmp-ами.</p><h3>#[derive(Debug)]</h3><p>Если вы пишете новый тип (скажем, структуру с кучей полей), то можно написать #[derive(Debug)], и Rust будет знать, как автоматически напечатать содержимое этого типа для отладки. Больше не нужно руками писать специальную функцию, которую затем придётся вызывать из gdb, только для того, чтобы посмотреть содержимое полей пользовательского типа.</p><h3>Замыкания</h3><p>Вам больше не придётся передавать указатели на функцию и user_data вручную.</p><h2>Заключение</h2><p>Я пока не попробовал «<a href="https://doc.rust-lang.org/book/second-edition/ch16-00-concurrency.html">fearless concurrency»</a>, где компилятор может предотвращать гонки данных в многопоточном коде. Я полагаю, что это в корне меняет положение дел для людей, которые пишут параллельный код на регулярной основе.</p><p>C — это старый язык с примитивными конструкциями и примитивными инструментами. Он хорошо подходил для небольших однопроцессорных Unix-ядер, которые работали в доверенных, академических средах. Но для современного программного обеспечения он больше не подходит.</p><p>Rust непросто освоить, но я уверен, что это того стоит. Сложность в том, что язык требует от вас глубокого понимания кода, который вы хотите написать. Я думаю, что это один из тех языков, которые делают вас лучше как программиста и позволяют решать более амбициозные проблемы.</p>]]></content:encoded>
    </item>
    <item>
      <title>Названы самые популярные IDE для разработки на C/C++ в 2018 году</title>
      <link>https://tproger.ru/news/most-popular-ide-for-c-cpp-2018</link>
      <comments>https://tproger.ru/news/most-popular-ide-for-c-cpp-2018?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Светлана Хачатурян]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/most-popular-ide-for-c-cpp-2018</guid>
      <description><![CDATA[<p>Опрос 1860 разработчиков сравнил IDE для C/C++. Среди названных лидеров — Visual Studio, QtCreator и Vim; отдельно отмечены C++Builder, CodeLite и NetBeans.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/most-popular-ide-for-c-cpp-2018">Названы самые популярные IDE для разработки на C/C++ в 2018 году</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 23 Feb 2018 08:21:38 GMT</pubDate>
      <content:encoded><![CDATA[<p>Исследователь Дэвид Коппола проанализировал данные о самых используемых IDE для разработки на C/C++ и <a href="http://blog.davidecoppola.com/2018/02/market-share-most-used-c-cpp-ides-in-2018-statistics-estimates/">представил</a> свою версию рейтинга инструментов.</p><h3>Результаты</h3><p>Согласно проведённому опросу, список самых популярных сред разработки выглядит следующим образом:</p><figure><img src="https://media.tproger.ru/uploads/2018/02/Snimok-jekrana-2018-02-22-v-23.27.01.jpg" alt="" /></figure><p>Второе место занимает обычный текстовый редактор <a href="https://tproger.ru/translations/vim-for-beginners/">Vim</a>. Его пользователи предпочитают «прикручивать» к программе разные расширения для работы с конкретными языками.</p><figure><img src="https://media.tproger.ru/uploads/2018/02/market_share_cpp_ides_pie-1.png" alt="" /></figure><p>К «другим» отнесены программы, за которые проголосовало менее 1 % разработчиков. Самыми примечательными представителями этой группы исследователь называет некогда востребованный C++Builder, а также CodeLite и NetBeans, которые попали в этот список наравне с редакторами Atom и Notepad++.</p><h3>Оценка количества разработчиков</h3><p>Отправной точкой этого исследования послужило примерное число разработчиков ПО в мире. По <a href="https://evansdata.com/reports/viewRelease.php?reportID=9">данным</a> Evans Data, в 2017 году их было 22 миллиона человек в 40 странах мира.</p><figure><img src="https://media.tproger.ru/uploads/2018/02/evansdata_number_software_developers.png" alt="" /></figure><p>Согласно <a href="https://tproger.ru/news/tiobe-february-2018/">индексу TIOBE</a>, приблизительное число программистов на C/C++ составляет около 3,5 миллионов человек. По <a href="https://blogs.msdn.microsoft.com/zxue/2016/10/24/how-many-developers-use-c-vs-c-vs-other-programming-languages/">словам</a> старшего менеджера Microsoft Бенжамина Сюэ (Benjamin Xue), в 2016 году более 1,5 миллионов разработчиков писали на C++ в Visual Studio. JetBrains <a href="https://blog.jetbrains.com/clion/2015/07/infographics-cpp-facts-before-clion/">говорит</a>, что в 2015 году на C и C++ писало более 6 миллионов человек. А опрос Дэвида Копполы дополнил картину, и исследователь пришёл к цифре в 5,1 миллиона разработчиков, пишущих на C/C++, по всему миру.</p><p>Исходя из этих вычислений, автор исследования определил примерное число кодеров, использующих каждую из 5 самых востребованных сред разработки:</p><figure><img src="https://media.tproger.ru/uploads/2018/02/Snimok-jekrana-2018-02-23-v-0.03.14.jpg" alt="" /></figure><p>Всего в опросе Копполы приняли участие 1860 человек, 87 % из которых — пользователи Reddit. Статистическая погрешность полученных значений составляет около 2,99 % с доверительным интервалом 99 %.</p><p>Языки C/C++ весьма популярны. При этом они <a href="https://tproger.ru/news/codingame-developers-survey-2018/">входят</a> в список самых нелюбимых инструментов для разработки по версии CodinGame.</p>]]></content:encoded>
    </item>
    <item>
      <title>Январский рейтинг языков программирования TIOBE: Си объявлен языком 2017 года</title>
      <link>https://tproger.ru/news/tiobe-january-2018</link>
      <comments>https://tproger.ru/news/tiobe-january-2018?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Светлана Хачатурян]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/tiobe-january-2018</guid>
      <description><![CDATA[<p>В январском рейтинге TIOBE язык Си получил звание языка 2017 года, а Python и Erlang заметно поднялись; R, Kotlin и другие языки тоже изменили позиции.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/tiobe-january-2018">Январский рейтинг языков программирования TIOBE: Си объявлен языком 2017 года</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 04 Jan 2018 18:57:25 GMT</pubDate>
      <content:encoded><![CDATA[<p>Старичок Си за прошедшие 12 месяцев успешнее всех пробился к вершинам рейтинга, именно поэтому ему присвоено почетное звание «Язык 2017 года» по версии TIOBE.</p><figure><img src="https://media.tproger.ru/uploads/2018/01/Snimok-jekrana-2018-01-04-v-20.54.06.jpg" alt="" /></figure><p>+ 1,69 % за год — не такая уж внушительная цифра для языка года, так что, по мнению аналитиков TIOBE, языку Си удалось победить только за счет отсутствия выдающихся конкурентов. Следом за ним успешно растут рейтинги Python (+ 1,21 %) и Erlang (+ 0,98 %).</p><p>Эксперты утверждают, что такой подъем весьма примечателен для Си, особенно после резкого падения интереса к нему в 2015 году. Три года назад он обладал рейтингом в 17 %, а за последующие 18 месяцев успел потерять целых 10 %. Вероятной причиной «возрождения» аналитики называют его огромную популярность в сферах производства и машиностроения.</p><figure><img src="https://media.tproger.ru/uploads/2018/01/Snimok-jekrana-2018-01-04-v-21.27.38.jpg" alt="" /></figure><p>Примечательные «скачки» популярности 2017 года принадлежат языкам R (переместившемуся с 16 на 8 место), Erlang (с 44 на 23) и Kotlin (с 89 на 39). Подающими надежды языками TIOBE назвал Julia, Hack, Rust и Kotlin, которым в ушедшем году так и не удалось войти даже в тридцатку лучших.</p><p>Напомним, что TIOBE отслеживает статистику поисковых запросов по языкам программирования и в начале каждого месяца <a href="https://www.tiobe.com/tiobe-index/">представляет</a> визуализированные интерактивные рейтинги самых популярных из них.</p>]]></content:encoded>
    </item>
    <item>
      <title>Макросы в Си: как, когда и зачем?</title>
      <link>https://tproger.ru/translations/c-macro</link>
      <comments>https://tproger.ru/translations/c-macro?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Андрей Селивестров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/c-macro</guid>
      <description><![CDATA[<p>Макросы в Си заменяют код после сборки, а функции выполняются отдельно со своим стековым кадром; сравнение показывает риски и области применения.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/c-macro">Макросы в Си: как, когда и зачем?</a>»</p>]]></description>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Для продолжающих]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 21 Dec 2017 16:10:06 GMT</pubDate>
      <content:encoded><![CDATA[<p>Программисты Си, дойдя до определённого уровня квалификации, обязательно сталкиваются с одной из особенностей этого языка — <a href="https://msdn.microsoft.com/ru-ru/library/503x3e3s.aspx">макросами</a>. Почти во всех других языках аналога макросов нет. И это неспроста. Использование макросов может оказаться весьма небезопасным. В них скрывается ряд особенностей, специфика которых не всегда лежит на поверхности.</p><p>Прим. перев. Макросы в таких языках, как Lisp, Scala и Rust, во многом лишены тех проблем и недостатков, которые описаны в этой статье.</p><h2>Макросы и функции</h2><p>При первом знакомстве макросы могут показаться обычными вызовами функций. Конечно, у них немного странный синтаксис, но они «ведут себя» как обычные функции. Тогда в чём разница?</p><p>Макрос можно условно назвать функцией обработки и замены программного кода: после сборки программы макросы заменяются макроопределениями. Вот как это выглядит:</p><p>Этот код преобразуется в следующий:</p><p>При вызове же функции под неё выделяется новый <a href="https://goo.gl/hjheiy">стековый кадр</a>, и она выполняется самостоятельно и не зависит от места в коде, откуда была вызвана. Таким образом, переменные с одинаковыми именами в разных функциях не вызовут ошибку, даже если вызывать одну функцию из другой.</p><p>Но если попытаться проделать такой же трюк с помощью макроса, то во время компиляции будет выброшена ошибка, так как обе переменные в итоге будут находиться в одной функции:</p><figure><img src="https://media.tproger.ru/uploads/2017/12/cmacros_1.png" alt="" /></figure><p>Более того, функции выполняют проверку типов: если функция ожидает на входе строку, а получает число, будет выброшена ошибка (или, по крайней мере, предупреждение, в зависимости от компилятора). Макросы в то же время просто заменяют аргумент, который им передан.</p><p>И, наконец, макросы не подлежат отладке. В отладчике можно войти в функцию и пройтись по её коду, а вот с макросами такое не пройдёт. Поэтому, если макрос почему-то сбоит, единственный способ выявить проблему — переходить к его определению и разбираться уже там.</p><p>Прим. перев. Чтобы не переходить к определению каждого макроса, можно попросить компилятор раскрыть макросы — это можно сделать с помощью команды gcc -E source.c. Имейте в виду, что если вы включаете в свой код с помощью #include стандартные заголовочные файлы, после препроцессинга в коде может оказаться много тысяч строк, так что стоит перенаправить вывод компилятора в файл.</p><p>Тем не менее, можно выделить одно явное преимущество макросов перед функциями — производительность. Макрос быстрее, чем функция. Как уже упоминалось выше, под функцию выделяются дополнительные ресурсы, которые можно сэкономить, если использовать макросы. Это преимущество может сыграть весомую роль в системах с ограниченными ресурсами (например, в очень старых микроконтроллерах). Но даже в современных системах программисты производят оптимизации, используя макросы для небольших процедур.</p><p>Прим. перев. Интересный подход к оптимизации использования ресурсов в программе на Си рассмотрен в <a href="https://tproger.ru/translations/art-of-structure-packing/">другой нашей статье</a>.</p><p>В C99 и C++ существует альтернатива макросам — встраиваемые (inline) функции. Если добавить ключевое слово inline перед функцией, компилятору будет дано указание включить тело функции в место её вызова (по аналогии с макросом). При этом встраиваемые функции могут быть отлажены, и у них есть проверка типов.</p><p>Однако ключевое слово inline — это просто подсказка для компилятора, а не строгое правило, и компилятор может проигнорировать эту подсказку. Чтобы этого не произошло, в gcc есть атрибут always_inline, который заставляет компилятор встроить функцию.</p><p>Встраиваемые функции — отличная штука, которая, как может показаться, делает использование макросов нецелесообразным. Однако это не совсем так.</p><h2>Когда использовать макросы в Cи</h2><h3>Передача аргументов по умолчанию</h3><p>В C++ есть весьма удобный инструмент, которого нет в Си, — <a href="https://goo.gl/MCsJFn">аргументы по умолчанию</a>:</p><p>В Си задача опциональных аргументов может быть решена с помощью макросов:</p><p>Этот код довольно безопасен и не скрывает никаких подводных камней (их мы обсудим далее). Конечно, эту задачу можно также решить с помощью функции, но она достаточно тривиальна, чтобы нести накладные расходы при использовании функций. Макрос справляется с ней на ура.</p><h3>Использование отладочных строк</h3><p>Некоторые компиляторы предопределяют макросы, которые нельзя использовать в функциях: __FILE__, __LINE__, __func__.</p><p>Их можно включать в определения макросов, используемых для отладки:</p><figure><img src="https://media.tproger.ru/uploads/2017/12/cmacros_2.png" alt="" /></figure><p>В итоге получается интересный способ ведения логов.</p><h3>Модификация синтаксиса</h3><p>Это очень мощная особенность макросов. Используя её, можно создать свой собственный синтаксис.</p><p>Например, в Cи нет конструкции foreach. Но её можно создать через макрос:</p><p>В этой вставке кода определена структура, содержащая <a href="https://tproger.ru/translations/linked-list-for-beginners/">связный список</a>. Предполагая, что его узлы заполнены, можно пройтись по нему с помощью LIST_FOREACH так же, как и при использовании foreach в современных языках.</p><p>Эта техника действительно очень эффективна и при правильном использовании может дать довольно хорошие результаты.</p><h2>Другие типы макросов</h2><p>Помимо макросов, которые подменяют функции, есть и другие очень полезные директивы препроцессора. Вот некоторые из наиболее часто используемых:</p><ul><li>#include — включить содержимое стороннего файла в текущий файл,</li><li>#ifdef — задать условие для компиляции,</li><li>#define — определить константу (и, конечно же, макрос).</li></ul><p>#ifdef играет ключевую роль при создании заголовочных файлов. Использование этого макроса гарантирует, что заголовочный файл включён только один раз:</p><p>Стоит отметить, что основное предназначение #ifdef — условная компиляция блоков кода на основе некоторого условия. Например, вывод отладочной информации только в режиме отладки:</p><figure><img src="https://media.tproger.ru/uploads/2017/12/cmacros_3.png" alt="" /></figure><p>Прим. перев. С помощью #ifdef также довольно часто задаётся условие для компиляции на различных версиях ОС и архитектурах: #ifdef _WIN32, #ifdef _WIN64, #ifdef __linux__ и так далее.</p><p>Как правило, для определения констант используется #define, но в некоторых проектах его заменяют на const и перечисления (enum). Однако при использовании любой из этих альтернатив есть свои преимущества и недостатки.</p><p>Использование ключевого слова const, в отличие от макроподстановки, позволяет произвести проверку типов данных. Но в Cи это создаёт не совсем полноценные константы. Например, их нельзя использовать в операторе switch-case и для определения размера массива.</p><p>Прим. автора  В C++ переменные, определённые ключевым словом const, являются полноценными константами (их можно использовать в приведённых выше случаях), и настоятельно рекомендуется использовать именно их, а не #define.</p><p>Перечисления в то же время — полноценные константы. Они могут использоваться в операторах switch-case и для определения размера массива. Однако их недостаток заключается в том, что в перечислениях можно использовать только целые числа. Их нельзя использовать для строковых констант и констант с плавающей запятой.<br />Вот почему использование #define — оптимальный вариант, если нужно достичь единообразия в определении различного рода констант.</p><p>Таким образом, у макросов есть свои преимущества. Но использовать их нужно весьма аккуратно.</p><h2>Подводные камни при использовании макросов</h2><h3>Отсутствие скобок</h3><p>Наиболее распространённая ошибка, которую допускают при использовании макросов, — отсутствие скобок вокруг аргументов в определениях макросов. Поскольку макросы подставляются непосредственно в код, это может вызвать неприятные побочные эффекты:</p><p>В этом примере выполняется вычисление MULTIPLY(x + 5) и ожидаемый результат — 50. Но в процессе подстановки произойдёт следующее преобразование:</p><p>MULTIPLY(x + 5) -&gt; (x + 5 * 5)</p><p>Как несложно подсчитать, данное выражение выдаст не 50, а 30.</p><p>А вот как выполнить данную задачу правильно:</p><h3>Инкремент и декремент</h3><p>Допустим, есть такой код:</p><p>Здесь можно ожидать, что x будет увеличен на единицу и будет равен 6, а результат — 5. Но вот что получится в реальной жизни:</p><figure><img src="https://media.tproger.ru/uploads/2017/12/cmacros_4.png" alt="" /></figure><p>Виновата всё та же макроподстановка: ABS(x++) -&gt; ((x++) &lt; 0 ? - (x++): (x++))</p><p>Как видно, x увеличивается на единицу в первый раз при проверке и во второй раз при определении результата, что и приводит к соответствующим итогам.</p><h3>Передача вызовов функций</h3><p>Использованием функции в коде никого не удивишь. Равно как и передачей результата одной функции в виде аргумента для другой. Часто это делается так:</p><p>И в этой вставке кода всё в порядке. Но, когда это же производится с помощью макроса, можно столкнуться с серьёзными проблемами производительности. Допустим, есть вот этот код:</p><p>Здесь определена рекурсивная функция sum_chars. Она вызывается один раз для первой строки (str1) и другой раз — для второй (str2). Но, если передать вызовы функций, как аргументы для макроса, будет выполнено три рекурсивных вызова вместо двух. Для больших структур данных это станет узким местом производительности. Особенно, если макрос используется внутри рекурсивной функции.</p><h3>Многострочные макросы</h3><p>Программисты не всегда используют фигурные скобки вокруг единичных команд в циклах и условных операторах. Но, если произвести макроподстановку внутри этого блока, и этот макрос будет содержать несколько строк, это приведёт к весьма интересным результатам:</p><p>Во вставке кода выше нет фигурных скобок в первом цикле и, так как макрос заменяет одну строку несколькими, только первое выражение в макросе выполняется в цикле. Следовательно, это приведёт к бесконечному циклу, так как i никогда не увеличится.</p><p>Прим. перев. Эту проблему также можно решить с помощью упомянутого выше трюка с do {} while (0).</p><p>Именно из-за таких особенностей многие стараются избегать использования макросов.</p><h2>Хорошая практика</h2><p>Чтобы свести к минимуму проблемы, вызванные использованием макросов, хорошей практикой будет использование единого подхода для определения макросов в вашем коде. Каким будет этот подход, не имеет значения. Есть проекты, в которых все макроопределения объявлены в верхнем регистре. В некоторых проектах в начале имени макроса используют букву «m». Выберите себе любой подход, но этот подход должен быть таким, чтобы и вы, и другой программист, который будет работать с вашим кодом, сразу понимал, что имеет дело с макросами.</p><p>Прим. перев. Другие полезные практики оформления кода можно посмотреть в <a href="https://tproger.ru/translations/learn-basic-c-coding-rules-from-open-source-projects/">нашей статье</a>.</p><h2>Вывод</h2><p>В большинстве случаев программисты предпочитают использовать функции, поскольку макросы скрывают некоторые серьёзные побочные эффекты. Тем не менее, использование макросов иногда более целесообразно. В этом случае нужно соблюдать правила их именования и учитывать специфику их использования, рассмотренную в статье.</p>]]></content:encoded>
    </item>
    <item>
      <title>JetBrains выпустила масштабное обновление CLion 2017.3</title>
      <link>https://tproger.ru/news/clion-2017-3</link>
      <comments>https://tproger.ru/news/clion-2017-3?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Светлана Хачатурян]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/clion-2017-3</guid>
      <description><![CDATA[<p>В CLion 2017.3 JetBrains исправила ошибки анализа кода и улучшила поддержку возможностей C++, а также обновила конфигурацию пользовательского интерфейса.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/clion-2017-3">JetBrains выпустила масштабное обновление CLion 2017.3</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 03 Dec 2017 16:26:38 GMT</pubDate>
      <content:encoded><![CDATA[<p>Компания JetBrains <a href="https://blog.jetbrains.com/clion/2017/11/clion-2017-3-cpp-support-valgrind-memcheck-boost-test/">представила</a> новую версию интегрированной среды разработки для языка С++. Улучшения коснулись поддержки функциональности ЯП и конфигурации пользовательского интерфейса.</p><h3>Поддержка функций языка</h3><ul><li>Полностью переработаны процедуры обработки списков инициализации. Больше никаких навязчивых ложных предупреждений вроде «слишком много аргументов» или «нет совпадающего конструктора». Помимо всего прочего, устранены неисправности с переменными типа auto и отображением некорректных сообщений об ошибках: <a href="https://media.tproger.ru/uploads/2017/12/uniform_init.png"></a></li><li>Усовершенствованы процедуры анализа кода и навигации. В частности, устранены проблемы, связанные с некорректной порядковой обработкой: <a href="https://media.tproger.ru/uploads/2017/12/using_ns.png"></a></li><li>Добавлена поддержка расширений MSVC, существенно снижающая вероятность отображения ложных сообщений об ошибках.</li><li>Реализована поддержка библиотеки JUCE для разработки кросс-платформенных аудио-модулей. <a href="https://media.tproger.ru/uploads/2017/12/JUCE_namespaces.png"></a></li><li>Добавлена поддержка объявления дружественного синтаксиса C++11.</li><li>Реализована поддержка макроса __COUNTER__:</li><li>Добавлена возможность генерации дефиниций (Ctrl+Shift+D в Linux/Windows, ⇧+⌘+D в macOS) для шаблонов функций.</li><li>Реализована функция автоматического преобразования блоковif-else после инвертирования условия: <a href="https://media.tproger.ru/uploads/2017/12/invert_if-1.gif"></a></li><li>Внедрен кросс-платформенный динамический анализатор кода Valgrind Memcheck: <a href="https://media.tproger.ru/uploads/2017/12/valgrind_memcheck.gif"></a></li><li>Добавлена поддержка фреймворка для тестирования Boost.Test: <a href="https://media.tproger.ru/uploads/2017/12/boost_test.gif"></a></li><li>Реализована возможность настраивать наборы инструментов для разных проектов. Пример персональной настройки наборов в macOS: <a href="https://media.tproger.ru/uploads/2017/12/BF9EBFF1-BAA6-4710-BDAD-2E08C01B2443.png"></a>И Windows:<a href="https://media.tproger.ru/uploads/2017/12/BDE9279F-B65B-484C-AA1C-3297BC21FF5D.png"></a></li></ul><p>С другими изменениями можно также ознакомиться в традиционном кратком видео-обзоре:</p><p>Более подробный список нововведений <a href="https://www.jetbrains.com/clion/whatsnew/">доступен</a> на официальной странице обновления.</p>]]></content:encoded>
    </item>
    <item>
      <title>Интересные проекты: математическая C-библиотека для разработки видеоигр</title>
      <link>https://tproger.ru/articles/mathc-by-ferreiradaselva</link>
      <comments>https://tproger.ru/articles/mathc-by-ferreiradaselva?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вячеслав Шарунов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/mathc-by-ferreiradaselva</guid>
      <description><![CDATA[<p>Проект MATHC содержит математические объекты на чистом C, поддерживает стандарт C99 и использует тип float для разработки игр с OpenGL.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/mathc-by-ferreiradaselva">Интересные проекты: математическая C-библиотека для разработки видеоигр</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Pet-проекты]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 30 Nov 2017 10:09:24 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сегодня мы рассмотрим проект <a href="https://github.com/ferreiradaselva/mathc">MATHC</a>. По своей сути, это простая математическая библиотека, которая может быть использована для разработки 2D- и 3D-игр. Она содержит реализации следующих математических объектов на чистом С:</p><ul><li>2D- и 3D-векторы;</li><li><a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%B2%D0%B0%D1%82%D0%B5%D1%80%D0%BD%D0%B8%D0%BE%D0%BD">кватернионы</a>;</li><li>матрицы;</li><li><a href="http://easings.net/ru">функции плавности</a>.</li></ul><p>Реализация объектов поддерживает как стандарт С99, так и более новые.</p><h3>Тип float</h3><p>Каждая структура и функция библиотеки использует тип float, поскольку в большинстве своём в разработке 2D- и 3D-игр при помощи OpenGL применяется именно этот тип данных.</p><h3>Передача по значению или по указателю</h3><p>Для функций, принимающих в качестве параметров структуры, предусмотрено две версии реализации. Первая — когда структура передаётся по значению, вторая — по указателю. Второй вид функций имеет префикс p перед именем типа (pvector2, pvector3, pquaternion и pmatrix), а результат записывается в передаваемый аргумент *result.</p><h3>Векторы</h3><p>Все векторы (2D, 3D и кватернионы) имеют вид структур типа struct vec. Отметим, что компонента z может быть использована и для 2D-векторов, поскольку она применяется в OpenGL для проверки глубины. Компонента w используется только для описания кватерниона.</p><h3>Матрицы</h3><p>Все матрицы в библиотеке имеют размер 4×4. В MATHC также реализованы функции для настройки матриц модели, мира и проекции. Обычно матрица мира используется для изменения множества вершин на стороне клиента или на графическом процессоре. Если вы хотите изменить вершины на стороне клиента, то используйте функции matrix_multiply_f4() или pmatrix_multiply_f4() для изменения массива с 4 float-элементами:</p><p>Если вы хотите изменить вершины на стороне GPU, то используйте функции matrix_to_array() или pmatrix_to_array() для перевода матрицы в массив с 16 float-элементами:</p><h3>Функции плавности</h3><p>Функции плавности полезны для анимации. Библиотечная реализация функций основана на <a href="http://easings.net/ru">их описании</a>. Функции принимают значения от 0.0f до 1.0f и возвращают значения внутри этого же диапазона. Однако в некоторых из функций возвращаемое значение экстраполирует этот диапазон.</p><h3>Лицензия MATHC</h3><p>Исходный код проекта подчиняется лицензии <a href="https://ru.wikipedia.org/wiki/%D0%9B%D0%B8%D1%86%D0%B5%D0%BD%D0%B7%D0%B8%D1%8F_zlib">ZLIB</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Интересные проекты: рендеринг изображений ASCII-символами</title>
      <link>https://tproger.ru/articles/ascii-art-by-symisc</link>
      <comments>https://tproger.ru/articles/ascii-art-by-symisc?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Максим Леонов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/ascii-art-by-symisc</guid>
      <description><![CDATA[<p>Однофайловая библиотека ASCII Art преобразует изображение или видеокадр в печатные ASCII-символы в реальном времени через дерево решений.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/ascii-art-by-symisc">Интересные проекты: рендеринг изображений ASCII-символами</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Pet-проекты]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 26 Nov 2017 10:08:31 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://github.com/symisc/ascii_art">ASCII Art</a> представляет собой однофайловую библиотеку C/C++, которая позволяет преобразовывать изображение или видеокадр в печатные символы ASCII в режиме реального времени. При этом используется одно дерево решений. Производительность в реальном времени достигается за счет использования сравнения интенсивности пикселей внутри внутренних узлов дерева.</p><h3>Как работает алгоритм</h3><p>При использовании изображения или видеокадра выполняются следующие действия:</p><ol><li>Входное изображение разбивается на прямоугольные ячейки одинакового размера. Размер сетки соответствует высоте и ширине одной ячейки (т.е. символу шрифта), полученным из кодовой книги на этапе обучения.</li><li>Для каждой ячейки из кодовой книги выбирается символ, который заменит в ней «сырые» пиксели. Этим занимается дерево решений, в которое подаются эти пиксели.</li><li>Большой набор изображений переводится в ASCII с учётом <a href="https://ru.wikipedia.org/wiki/SSIM">индекса структурного сходства</a> и используется в качестве обучающего набора данных.</li></ol><h3>Руководство по началу работы</h3><p>Встроить библиотеку в ваше приложение не составит труда. Для этого нужно лишь добавить ascii_art.c и его заголовочный файл в ваше дерево исходного кода и <a href="https://pixlab.io/art">скачать</a> шестнадцатеричную модель, а также выполнить следующие вызовы API:</p><ol><li>Сначала вызовите <a href="https://pixlab.io/art">AsciiArtInit</a>, чтобы инициализировать структуру ascii_render, определенную в заголовочном файле ascii_art.h.</li><li>Подготовьте изображение, которое нужно обработать, переведя его в оттенки серого. Для этого можно использовать внешнюю библиотеку вроде <a href="https://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html">cvtColor</a> из OpenCV или встроенный интерфейс <a href="https://pixlab.io/art">AsciiArtLoadImage</a>.</li><li>Выделите буфер, достаточно большой для хранения всех выходных данных. Количество необходимых байтов можно получить через интерфейс <a href="https://pixlab.io/art">AsciiArtTextBufSize</a>. Этот шаг является необязательным, если вы хотите не выводить текст, а получить двоичное изображение из ASCII-символов.</li><li>Наконец, преобразуйте входное изображение в символы ASCII с помощью <a href="https://pixlab.io/art">AsciiArtRender</a>.</li></ol><p>Ниже представлена простая <a href="https://github.com/symisc/ascii_art/blob/master/sample.c">программа</a> на С, которая которая демонстрирует типичное использование этих интерфейсов.</p><p>Также доступна <a href="https://art.pixlab.io">демо-версия</a> программы.</p>]]></content:encoded>
    </item>
    <item>
      <title>Интересные проекты: облачная файловая система pingfs</title>
      <link>https://tproger.ru/articles/pingfs-by-yarrick</link>
      <comments>https://tproger.ru/articles/pingfs-by-yarrick?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вячеслав Шарунов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/pingfs-by-yarrick</guid>
      <description><![CDATA[<p>Файловая система pingfs использует ICMP Echo-пакеты и FUSE для хранения данных в Интернете; проект поддерживает IPv4 и IPv6 и требует права суперпользователя.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/pingfs-by-yarrick">Интересные проекты: облачная файловая система pingfs</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Инструменты командной строки]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Pet-проекты]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 14 Nov 2017 09:59:59 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://github.com/yarrick/pingfs">pingfs</a> — это аналог привычной файловой системы, но с одним отличием. Все данные хранятся в сети Интернет в качестве <a href="https://ru.wikipedia.org/wiki/ICMP">ICMP</a> Echo-пакетов (пингов), «путешествующих» между компьютером пользователя и удалёнными серверами.</p><p>Проект реализован с использованием <a href="https://ru.wikipedia.org/wiki/%D0%A1%D1%8B%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D0%BA%D0%B5%D1%82">API сырых сокетов</a> и <a href="https://ru.wikipedia.org/wiki/FUSE_(%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C_%D1%8F%D0%B4%D1%80%D0%B0)">FUSE</a> (filesystem in userspace, файловая система в пользовательском пространстве), поэтому для полноценной работы и запуска проекта необходимы права суперпользователя. Linux является единственной ОС, на которой возможно запустить программу. Поддерживаются обе версии протокола удалённых хостов, IPv4 и IPv6.</p><h3>Работа с проектом</h3><p>Для компиляции проекта необходимо запустить make в корневой папке. Чтобы начать использование, необходимо:</p><ul><li>Создать текстовый файл с именами хостов и их IP-адресами;</li><li>Запустить программу в режиме root-пользователя при помощи команды: ./pingfs &lt;название файла&gt; &lt;точка монтирования&gt;. Программа начнёт проверку хостов на правильность их реакции посредством отправки нескольких пингов. На экран будет выведена некоторая информация и статистика, затем будет произведено монтирование файловой системы;</li><li>pingfs останется запущенным и будет печатать статистику по пакетам и байтам каждую секунду.</li></ul><p>Чтобы остановить работу программы:</p><ul><li>Нажмите Ctrl+C;</li><li>В противном случае, можно воспользоваться командой fusermount -u.</li></ul><h3>Поддерживаемые операции</h3><ul><li>Создание и удаление обычных файлов;</li><li>Листинг файлов;</li><li>Переименование файлов;</li><li>Чтение, запись и усечение файлов;</li><li>Настройка и получение прав на доступ к файлам.</li></ul><h3>Неподдерживаемые операции</h3><ul><li>Создание и удаление каталогов;</li><li>Создание жёстких и мягких ссылок на файлы;</li><li>Временные отметки (в этой версии они всегда равны 0).</li></ul><p>Автор проекта отмечает, что в настоящее время производительность обработки LAN-хостов слишком низкая. Передача данных между ними часто приводит к потере пакетов, поэтому используйте pingfs с осторожностью.</p><p>В качестве шутки над идеей проекта пользователи Reddit уже <a href="https://www.reddit.com/r/programming/comments/78apup/pingfs_a_filesystem_where_the_data_is_stored_only/">придумали</a> ему девиз:</p><blockquote>Где мои данные? Не могу сказать. Но они существуют? Надеюсь.</blockquote>]]></content:encoded>
    </item>
    <item>
      <title>Статический анализ кода: обзор инструмента OCLint</title>
      <link>https://tproger.ru/articles/oclint-by-ryuichi</link>
      <comments>https://tproger.ru/articles/oclint-by-ryuichi?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вячеслав Шарунов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/oclint-by-ryuichi</guid>
      <description><![CDATA[<p>Инструмент OCLint ищет баги и ошибки в программах на C, C++ и Objective-C, которые могут остаться незаметными для компилятора.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/oclint-by-ryuichi">Статический анализ кода: обзор инструмента OCLint</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Инструменты командной строки]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Objective-C]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Nov 2017 08:48:02 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="http://oclint.org/">OCLint</a> — инструмент, разработанный <a href="https://ryuichi.co/labs/">Ryuichi Laboratories</a>, который проверяет программы на С, С++ и Objective-C на наличие следующих багов и ошибок:</p><ul><li>пустые конструкции if/else/try/catch/finally;</li><li>неиспользуемые локальные переменные и параметры;</li><li>использование кода с высокой <a href="https://habrahabr.ru/company/intel/blog/106082/">цикломатической</a> и <a href="https://modess.io/npath-complexity-cyclomatic-complexity-explained/">NPath</a> сложностью;</li><li>избыточное использование конструкций if и ненужных скобок;</li><li><a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B4_%D1%81_%D0%B7%D0%B0%D0%BF%D0%B0%D1%88%D0%BA%D0%BE%D0%BC">код с запашком</a> — использование длинных методов и длинных списков параметров;</li><li>плохие практики написания кода — переназначение параметров, неправильное использование логики.</li></ul><h3>Функциональность OCLint</h3><p><a href="https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7_%D0%BA%D0%BE%D0%B4%D0%B0">Статический анализ кода</a> призван обнаруживать критические дефекты кода, которые не видны компилятору, но способны обрушить программу в будущем. OCLint автоматизирует процесс проверки кода при помощи расширенных функций:</p><ul><li>Динамическая загрузка правил в систему, даже во время выполнения;</li><li>Гибкие и расширяемые конфигурации программы гарантируют пользователю настройку поведения OCLint именно под нужды каждого;</li><li>Возможность вызова инструмента из командной строки вносит <a href="https://martinfowler.com/articles/continuousIntegration.html">непрерывную интеграцию</a> и постоянную проверку кода в процессе разработки. Это поможет исправлять все баги ещё на этапе разработки;</li><li>Снижена вероятность ложных срабатываний инструмента для избежания ситуаций, когда полезный код может быть помечен как избыточный;</li><li>Эффективность и точность инструмента основана на использовании <a href="https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE">абстрактного синтаксического дерева</a> исходного кода.</li></ul><h3>Установка инструмента</h3><p>OCLint является автономным инструментом, работающим на платформах Linux и macOS. Получить самую свежую версию 0.13 продукта вы можете, загрузив и самостоятельно скомпилировав <a href="http://oclint.org/docs/intro/build.html">исходный код</a>, либо уже <a href="https://github.com/oclint/oclint/releases">скомпилированные двоичные файлы</a> программы.</p><p>Процесс установки подробно <a href="http://docs.oclint.org/en/stable/intro/installation.html">описан</a> на специальной странице инструмента. Также доступно <a href="http://oclint.org/docs/intro/tutorial.html">руководство пользователя</a> с подробным описанием использования команд инструмента. Продукт распространяется под лицензией Modified BSD.</p>]]></content:encoded>
    </item>
    <item>
      <title>Курс «Углубленное программирование на C/С++»</title>
      <link>https://tproger.ru/video/c-cpp-advanced-programming</link>
      <comments>https://tproger.ru/video/c-cpp-advanced-programming?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дмитрий Баранчук]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/video/c-cpp-advanced-programming</guid>
      <description><![CDATA[<p>Русскоязычный курс «Технопарка Mail.Ru Group» развивает навыки C/C++ для серверной разработки и UNIX-подобных операционных систем.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/video/c-cpp-advanced-programming">Курс «Углубленное программирование на C/С++»</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Обучающие курсы]]></category>
      <category><![CDATA[Для продолжающих]]></category>
      <category><![CDATA[Видео]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 29 Sep 2017 19:25:40 GMT</pubDate>
      <content:encoded><![CDATA[<p>Русскоязычный курс проекта «Технопарк <a href="https://vk.com/away.php?to=http%3A%2F%2FMail.Ru&amp;post=-30666517_1500452&amp;cc_key=">Mail.Ru</a> Group», посвященный продвинутым аспектам программирования на языках C/C++. Курс записан в 2014 году, лектор — Алексей Петров.</p><p>Цель курса — формирование практических навыков и умений, необходимых специалистам по разработке программного обеспечения UNIX-подобных операционных систем для участия в проектах промышленной разработки среднего уровня сложности на языках C/C++, в том числе для замещения стажерских должностей разработчиков серверной части высоконагруженных приложений.</p><p>Смотрите еще больше обучающих материалов по языкам C и C++.</p>]]></content:encoded>
    </item>
    <item>
      <title>Курс «Основы программирования встраиваемых систем»</title>
      <link>https://tproger.ru/video/embedded-systems</link>
      <comments>https://tproger.ru/video/embedded-systems?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дмитрий Баранчук]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/video/embedded-systems</guid>
      <description><![CDATA[<p>Русскоязычный курс знакомит с микроконтроллерами и их применением в часах, роботах, автомобилях, медицинских приборах и системах умного дома.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/video/embedded-systems">Курс «Основы программирования встраиваемых систем»</a>»</p>]]></description>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Язык ассемблера]]></category>
      <category><![CDATA[Видео]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 29 Sep 2017 19:06:36 GMT</pubDate>
      <content:encoded><![CDATA[<p>Русскоязычный курс, открывающий своим слушателям удивительный мир микроконтроллеров. Среди окружающих нас приборов все сложнее встретить такие, в которых их нет. Часы и светофоры, системы освещения, электронные игрушки и роботы, телевизоры и пылесосы, микроволновки и чайники, автомобили и медицинские приборы, охранные системы и умные дома — все это оживает благодаря микроконтроллерам.</p><p>В курсе будут рассмотрены следующие темы:</p><ul><li>отличия микроконтроллеров от традиционных компьютеров;</li><li>обзор популярных семейств микроконтроллеров (ARM, AVR, MSP430 и др.) , их возможностей, а также проектов на их основе;</li><li>настройка среды разработчика и написание программ на Си и Ассемблер;</li><li>обзор периферийных интерфейсов и протоколов;</li><li>ввод/вывод общего назначения и подключение различных внешних устройств;</li><li>работа с прерываниями и таймерами;</li><li>сведения о начальной загрузке и инициализации контроллера.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>«Шелл» на С: пишем командную оболочку для Unix</title>
      <link>https://tproger.ru/translations/unix-shell-in-c</link>
      <comments>https://tproger.ru/translations/unix-shell-in-c?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Ярослав Сарницкий]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/unix-shell-in-c</guid>
      <description><![CDATA[<p>Многие считают, что сделать программу, которой будут пользоваться миллионы, очень трудно. Однако за любым, даже самым сложным, продуктом всегда стоит простая идея. Одним из них является командная оболочка, или «шелл». В этой статье мы расскажем, как написать упрощенную командную оболочку Unix на C.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/unix-shell-in-c">«Шелл» на С: пишем командную оболочку для Unix</a>»</p>]]></description>
      <category><![CDATA[Низкоуровневое программирование]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Для продолжающих]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 06 Sep 2017 18:10:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Многие считают, что сделать программу, которой будут пользоваться миллионы, очень трудно. Однако за любым, даже самым сложным, продуктом всегда стоит простая идея. Одним из них является командная оболочка, или «шелл». В этой статье мы расскажем, как написать упрощенную командную оболочку Unix на C.</p><p>Совет Не стоит сдавать или использовать (даже в изменённом виде) приведённый ниже код в качестве домашнего проекта в школе или вузе. Многие преподаватели знают об оригинальной статье и уличат вас в обмане.</p><h2>Жизненный цикл командной оболочки</h2><p>Оболочка выполняет три основные операции за время своего существования:</p><ol><li>Инициализация: на этом этапе она читает и исполняет свои файлы конфигурации. Они изменяют её поведение.</li><li>Интерпретация: далее оболочка считывает команды из stdin и исполняет их.</li><li>Завершение: после исполнения основных команд она исполняет команды выключения, освобождает память и завершает работу.</li></ol><p>Именно эти три операции мы будем использовать как основу для нашей командной оболочки. Мы не будем добавлять дополнительные файлы конфигурации и команду выключения. Будем лишь вызывать функцию цикла и завершать работу. Стоит отметить, что, с точки зрения архитектуры, жизненный цикл сложнее, чем просто цикл.</p><p>В примере выше можно увидеть функцию lsh_loop(), которая будет циклически интерпретировать команды. Реализацию рассмотрим чуть ниже.</p><h2>Базовый цикл командной оболочки</h2><p>В первую очередь нам нужно подумать о том, как программа должна запускаться. И здесь важно понимать, что делает оболочка во время цикла. Простой способ обработки команд состоит из трех шагов:</p><ol><li>Чтение: считывание команды со стандартных потоков.</li><li>Парсинг: распознавание программы и аргументов во входной строке.</li><li>Исполнение: запуск распознанной команды.</li></ol><p>Эта идея реализована в функции lsh_loop():</p><p>Пройдемся по коду. Первые несколько строк — это просто объявления. Цикл с постусловием более удобен для проверки состояния переменной, поскольку выполняется перед проверкой ее значения. Внутри цикла выводится приглашение ввода, вызываются функции для чтения входной строки и разбиения строки на аргументы, а затем исполняются аргументы. Далее освобождается память, выделенная под строку и аргументы. Стоит обратить внимание, что в коде используется переменная состояния, возвращаемая в lsh_execute() и определяющая, когда нужно выйти из функции.</p><h2>Чтение строки</h2><p>Чтение строки из стандартного потока ввода — это вроде бы просто, но в C это может вызвать много хлопот. Беда в том, что никто не знает заранее, сколько текста пользователь введет в командную оболочку. Нельзя просто выделить блок и надеяться, что пользователи не выйдут за него. Вместо этого нужно перераспределять выделенный блок памяти, если пользователи выйдут за его пределы. Это стандартное решение в C, и именно оно будет использоваться для реализации lsh_read_line().</p><p>В первой части много объявлений. Стоит отметить, что в коде используется старый стиль C, а именно объявление переменных до основной части кода. Основная часть функции находится внутри, на первый взгляд, бесконечного цикла while(1). В цикле символ считывается и сохраняется как int, а не char (EOF — это целое число, а не символ, поэтому для проверки используйте int). Если это символ перевода строки или EOF, мы завершаем текущую строку и возвращаем ее. В обратном случае символ добавляется в существующую строку.</p><p>Затем мы проверяем, выходит ли следующий символ за пределы буфера. Если это так, то перераспределяем буфер (при этом проверяем его на наличие ошибок распределения) и продолжаем исполнение.</p><p>Те, кто знаком с новыми версиями стандартной библиотеки C, могут заметить, что в stdio.h есть функция getline(), которая выполняет большую часть работы, реализованной в коде выше. Эта функция была расширением GNU для библиотеки C до 2008 года, а затем была добавлена в спецификацию, поэтому большинство современных Unix-систем уже идут с ней в комплекте.  С getline функция становится тривиальной:</p><h2>Парсинг строки</h2><p>Теперь нам нужно распарсить входную строку в список аргументов. Мы сделаем небольшое упрощение и запретим пользователю использовать кавычки и обратную косую черту в аргументах командной строки. Вместо этого для разделения аргументов мы просто будем использовать пробелы. Таким образом команда  echo "вот сообщение" будет вызывать команду echo не с одним аргументом "вот сообщение", а с двумя:"вот" и "сообщение".</p><p>Теперь всё, что нам нужно сделать — разбить строку на части, используя пробелы в качестве разделителей. Это значит, что мы можем использовать классическую библиотечную функцию strtok.</p><p>Реализация этой функции подозрительно похожа на lsh_read_line(), и это неспроста! Здесь используется та же стратегия, только вместо нуль-терминированного массива символов мы используем нуль-терминированный массив указателей.</p><p>Мы начинаем разбиение, вызывая strtok. Она возвращает указатель на первый кусок строки (токен). Вообще strtok() возвращает указатели на места в строке и помещает нуль-терминаторы в конце каждого токена. Эти указатели мы храним в отдельном массиве.</p><p>При необходимости мы перераспределим массив указателей. Повторяем процесс до тех пор, пока strtok не перестанет возвращать токены, и завершаем массив токенов нуль-терминатором.</p><p>Теперь у нас есть массив токенов, готовых к исполнению.</p><h2>Как командные оболочки запускают процессы</h2><p>Теперь мы добрались до самой сути того, что делает оболочка. Запуск процессов — это основная функция командных оболочек. Поэтому если вы создаёте оболочку, то должны точно знать, что происходит с процессами и как они запускаются. Именно поэтому сейчас мы поговорим о <a href="https://tproger.ru/translations/unix-basics/">процессах в Unix</a>.</p><p>В Unix есть только два способа запуска процессов. Первый (который не будем брать в счет) — это Init. Видите ли, когда загружается Unix-система, загружается её ядро. После загрузки и инициализации ядро запускает только один процесс, который называется Init. Этот процесс выполняется в течение всего времени работы компьютера, и  управляет загрузкой остальных процессов, которые необходимы для его работы.</p><p>Поскольку все остальные процессы не Init, остаётся только один практический способ запуска процессов: системный вызов fork(). Когда эта функция вызывается, операционная система делает дубликат процесса и запускает их параллельно. Первоначальный процесс называется «родительским», а новый — «дочерним». Дочернему процессу fork() возвращает 0, а родителю — идентификатор процесса (PID) его дочернего элемента. Таким образом, любой новый процесс можно создать только из копии уже существующего.</p><p>Это может показаться проблемой. Обычно, когда вы хотите запустить новый процесс, вам не нужна копия уже работающей программы — вы хотите запустить другую программу. Для этого нужно использовать системный вызов exec(). Он заменяет текущую запущенную программу совершенно новой. Это значит, что при вызове exec операционная система останавливает процесс, загружает новую программу и запускает ее на том же месте. Вызов exec() не возвращает процесс, если нет ошибки.</p><p>Благодаря этим двум системным вызовам и возможен запуск большинства программ в Unix. Сперва существующий процесс раздваивается на родительский и дочерний, а затем дочерний процесс использует exec() для замены себя новой программой. Родительский процесс может продолжать делать другие вещи, а также следить за своими дочерними элементами, используя системный вызов wait().</p><p>Да уж, информации немало. Давайте посмотрим на код запуска программы:</p><p>Эта функция принимает список аргументов, которые мы создали ранее. Затем она разворачивает процесс и сохраняет возвращаемое значение. Как только fork() возвращает значение, мы получаем два параллельных процесса. Дочернему процессу соответствует первое условие if (где pid == 0).</p><p>В дочернем процессе мы хотим запустить команду, заданную пользователем. Поэтому мы используем один из вариантов системного вызова exec, execvp. Разные варианты exec делают разные вещи. Одни принимают переменное количество строковых аргументов, другие берут список строк, а третьи позволяют указать окружение, в котором выполняется процесс. Этот конкретный вариант принимает имя программы и массив (также называемый вектором, отсюда 'v') строковых аргументов (первым должно быть имя программы). 'p' означает, что вместо предоставления полного пути к файлу программы для запуска мы укажем только её имя, а также скажем операционной системе искать её самостоятельно.</p><p>Если команда exec возвращает -1 (или любое другое значение), значит, произошла ошибка. Таким образом, мы используем perror для вывода сообщения об ошибке вместе с именем программы, чтобы было понятно, где произошла ошибка. Затем мы завершаем процесс, но так, чтобы программная оболочка продолжала работать.</p><p>Второе условие (pid &lt; 0) проверяет, произошла ли в процессе выполнения fork() ошибка. Если ошибка есть, мы выводим сообщение об этом на экран, но программа продолжает работать.</p><p>Третье условие означает, что вызов fork() выполнен успешно. Там находится родительский процесс. Мы знаем, что потомок собирается исполнить процесс, поэтому родитель должен дождаться завершения команды. Мы используем waitpid() для ожидания изменения состояния процесса. К сожалению, у waitpid() есть много опций (например, exec()). Процессы могут изменять свое состояние множеством способов, и не все состояния означают, что процесс завершился. Процесс может либо завершиться обычным путём (успешно либо с кодом ошибки), либо быть остановлен сигналом. Таким образом, мы используем макросы, предоставляемые waitpid(), чтобы убедиться, что процесс завершен. Затем функция возвращает 1 как сигнал вызывающей функции, что она снова может вывести приглашение ввода.</p><h2>Встроенные функции оболочки</h2><p>Возможно, вы заметили, что функция lsh_loop() вызывает lsh_execute(), но выше мы назвали нашу функцию lsh_launch(). Это было намеренно! Дело в том, что большинство команд, которые исполняет оболочка, являются программами — но не все. Некоторые из команд встроены прямо в оболочку.</p><p>Причина довольно проста. Если вы хотите сменить каталог, вам нужно использовать функцию chdir(). Дело в том, что текущий каталог является свойством процесса. Итак, допустим, вы написали программу cd, которая изменяет каталог. Она просто меняет свой текущий каталог и завершается, но текущий каталог родительского процесса не изменится. Вместо этого процесс оболочки должен исполнить chdir(), чтобы обновить свой текущий каталог. Затем, когда он запускает дочерние процессы, они также наследуют этот каталог.</p><p>Аналогично программа с именем exit не сможет выйти из командной оболочки, которая ее вызвала. Эта команда также должна быть встроена в оболочку. Кроме того, большинство оболочек настраиваются с помощью сценариев конфигурации, таких как ~/.bashrc. Эти сценарии используют команды, которые изменяют работу оболочки. Сами же команды могут изменить работу оболочки, если только они были реализованы внутри самой оболочки.</p><p>Соответственно, имеет смысл добавить некоторые команды в оболочку. В эту оболочку мы добавим cd, exit и help. А вот и реализация этих функций:</p><p>Код состоит из трёх частей. Первая часть содержит предваряющее объявление функций. Предваряющее объявление — это когда вы объявляете (но не определяете) что-то, чтобы можно было использовать это имя до его определения.lsh_help() — причина, по которой мы делаем это. Она использует массив встроенных функций, а сами массивы содержат lsh_help(). Самый простой способ разбить этот цикл зависимостей — это предваряющее объявление.</p><p>Следующая часть представляет собой массив имён встроенных команд, за которыми следует массив соответствующих функций. Это значит, что в будущем встроенные команды могут быть добавлены путем изменения этих массивов, а не большого оператора switch где-то в коде. Если вы смущены объявлением builtin_func, все в порядке. Это массив указателей на функции (которые принимают массив строк и возвращают int). Любое объявление, включающее указатели на функции в C, может стать действительно сложным.</p><p>Наконец, идет реализация каждой функции. Функция lsh_cd() сначала проверяет наличие своего второго аргумента и выводит сообщение об ошибке, если его нет. Затем она вызывает chdir(), проверяет наличие ошибок и завершает работу. Функция справки выводит информативное сообщение и имена всех встроенных функций. А функция выхода возвращает 0, как сигнал для окончания цикла команд.</p><h2>Объединение встроенных функций и процессов</h2><p>Последний недостающий фрагмент головоломки заключается в реализации функции lsh_execute(), которая либо запускает либо встроенный, либо другой процесс.</p><p>Код проверяет, является ли команда встроенной. Если это так, то запускает её, а в противном случае вызывает lsh_launch(), чтобы запустить процесс.</p><h2>Собираем все вместе</h2><p>Вот и весь код, который входит в командную оболочку. Если вы внимательно читали статью, то должны были понять, как работает оболочка. Чтобы испробовать оболочку (на Linux), вам нужно скопировать эти сегменты кода в файл main.c и скомпилировать его. Обязательно включите только одну реализацию lsh_read_line(). Вам нужно будет включить следующие заголовочные файлы:</p><ul><li>#include &lt;sys/wait.h&gt;waitpid() и связанные макросы</li><li>#include &lt;unistd.h&gt;chdir() fork() exec() pid_t</li><li>#include &lt;stdlib.h&gt;malloc() realloc() free() exit() execvp() EXIT_SUCCESS, EXIT_FAILURE</li><li>#include &lt;stdio.h&gt;fprintf() printf() stderr getchar() perror()</li><li>#include &lt;string.h&gt;strcmp() strtok()</li></ul><p>Чтобы скомпилировать файл, введите в терминале gcc -o main main.c, а затем ./main, чтобы запустить.</p><p>Кроме того, все исходники доступны <a href="https://github.com/brenns10/lsh/tree/407938170e8b40d231781576e05282a41634848c">на GitHub</a>.</p><h2>Подводя итоги</h2><p>Очевидно, что эта оболочка не является многофункциональной. Некоторые из ее упущений:</p><ul><li>аргументы разделяются только пробелами, нет поддержки кавычек или обратного слеша;</li><li>нет перенаправления и конвейеров;</li><li>мало встроенных функций;</li><li>нет подстановки имён файлов.</li></ul><p>Чтобы разобраться в системных вызовах, рекомендуем обратиться к мануалу: man 3p. Если вы не знаете, какой интерфейс вам предлагают стандартная библиотека C и Unix, советуем посмотреть <a href="http://pubs.opengroup.org/onlinepubs/9699919799/">спецификацию POSIX</a>, в частности раздел 13.</p>]]></content:encoded>
    </item>
    <item>
      <title>IEEE Spectrum опубликовал рейтинг языков программирования за 2017 год</title>
      <link>https://tproger.ru/news/ieee-spectrum-rating-2017</link>
      <comments>https://tproger.ru/news/ieee-spectrum-rating-2017?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Иван Кулешин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/ieee-spectrum-rating-2017</guid>
      <description><![CDATA[<p>В рейтинге IEEE Spectrum за 2017 год Python поднялся на два места, Swift вошёл в первую десятку, а Objective-C опустился на 26-ю позицию.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/ieee-spectrum-rating-2017">IEEE Spectrum опубликовал рейтинг языков программирования за 2017 год</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Swift]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Язык Си]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 23 Jul 2017 15:09:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>Журнал Spectrum, издаваемый Институтом инженеров электротехники и электроники (IEEE), <a href="http://spectrum.ieee.org/static/interactive-the-top-programming-languages-2017">опубликовал</a> новую редакцию рейтинга популярности языков программирования.</p><h3>Что изменилось?</h3><p>Популярность Python продолжила расти, и он переместился на два места вперед. Однако рейтинги четвёрки лидеров: Python, C, Java и C++ — не сильно различаются. В настоящее время, по меркам востребованных компаний, C на голову опережает Python.</p><p>C# вернулся в первую пятерку, забрав место, которое принадлежало R в прошлом году. Ruby, к сожалению, упал до 12-й позиции, но при этом он дал шанс Swift присоединиться к Go в первой десятке. Это впечатляет, ведь Swift дебютировал в рейтинге всего два года назад. Полная противоположность Swift — это Objective-C, он опустился аж до 26 места.</p><p>Уже второй год подряд в рейтинг не входят новые языки. Программисты заняты осваиванием уже созданных инструментов для работы с облачными и мобильными приложениями.</p><p>Говоря о ветеранах среди языков программирования, стоит отметить присутствие в середине рейтинга такого языка, как Fortran (на 28 месте). На 35 месте расположился Lisp, а на 40 — Cobol. Приятно осознавать, что языки, которые использовались десятилетиями, по-прежнему вызывают интерес.</p><p>Для создания своего рейтинга специалисты IEEE <a href="http://spectrum.ieee.org/ns/IEEE_TPL_2017/methods.html">используют</a> 12 различных метрик из 10 источников. Основные показатели — это поисковая выдача по запросу с названием языка программирования и требования работодателей. Также учитываются данные Google Trends и упоминания в социальных сетях.</p>]]></content:encoded>
    </item>
  </channel>
</rss>