Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Бесплатная лицензия PVS-Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

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

Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
Как различить C и C++ разработчиков по …

Как различить C и C++ разработчиков по их коду

12 Май 2022
Автор:

Так уж случилось, что я пишу код для разных IoT-железок, связанных с электричеством, типа зарядных станций автомобилей. Поскольку аппаратных ресурсов, как правило, вполне достаточно, то основным фокусом является не экономия каждого байта и такта процессора, а понятный и надежный код. Поэтому в проекте разрабатывают под Embedded Linux и в качестве основного языка используют C++ в его современном варианте - C++17, активно поглядывая на фичи из стандарта 20-го года и новее (подождите, кто сказал Rust?).

0946_C_Cpp_developers_difference_ru/image1.png

Мы опубликовали и перевели эту статью с разрешения правообладателя. Автор статьи – Кирилл Овчинников (kirill.ovchinn@gmail.com). Оригинал опубликован на сайте Habr.

0946_C_Cpp_developers_difference_ru/image2.png

Иногда запускаются новые проекты на той же платформе, с теми же процессами и с переиспользованием многих уже существующих компонентов, и тогда в эти проекты мы ищем программистов, с учетом вышесказанного - программистов на C++. В embedded, тем не менее, чистый C все еще очень популярен, и нередко собеседоваться на вакансию C++ Developer'а приходят именно сишники. Логика у человека простая: языки, на первый взгляд, довольно близкие и почти обратно-совместимые, базовый синтаксис одинаков, про ООП кандидат что-то слышал, и значит, основная база уже есть, и он сможет легко освоить C++ за 21 день в процессе работы, поэтому можно наплести про "с C++ тоже работал", начать писать на "Си с классами" и все получится. В то время как в новой команде таких "бывших сишников" уже и так набралось несколько, и такой кандидат нам уже не подойдет, на оставшиеся позиции нужен именно опытный плюсовик-затейник, который будет активно внедрять best practices и наставлять на code review на путь истинный менее опытных коллег.

0946_C_Cpp_developers_difference_ru/image3.png

К счастью, несмотря на кажущуюся схожесть языков, чем лучше ты знаешь каждый из них, тем больше ты понимаешь, что они очень разные. И в итоге разработчика на C от разработчика на C++ можно легко отличить на интервью или ревью, и команда даже на основе своего опыта и своих предпочтений набросала список звоночков, которые выдают сишников при собеседовании на C++-позицию и вызывают необходимость уже более детального разговора на тему "а почему ты сделал так". Итак, признаки того, что разработчик программирует не на C++, а на "C с классами":

  • Использует <stdint.h>, <string.h>, <stdio.h> вместо <cstdint>, <cstring>, <cstdio>;
  • Использует malloc() и free() кроме явно предназначенных для этого мест (типа кастомных аллокаторов);
  • Использует ручное управление памятью с new и delete, вместо RAII и умных указателей;
  • Использует char*-строки и функции <string.h> вместо std::string и std::string_view; (единственное исключение - строковые константы через constexpr). Использует функции из <time.h> вместо std::chrono. Использует atoi() вместо stoi(). Использует функции из <stdio.h> вместо std::filesystem и потоков ввода-вывода. Использует <pthread.h> вместо std::thread;
  • Когда нужно имплементировать алгоритм или контейнер независимый от типа данных, которыми он оперирует, использует #define-макросы или void*-указатели вместо темплейтов;
  • Для объявления констант использует #define вместо const и constexpr;
  • Использует C-style массивы вместо std::array;
  • Использует NULL вместо nullptr;
  • Пишет (type)something вместо static_cast<type>(something);
  • Использует простые указатели на функции вместо std::function;
  • Использует enum вместо enum class даже для простых перечислений;
  • Для функций, не изменяющих состояние объектов, не использует const при объявлении; Для конструкторов забывает explicit. Для деструкторов забывает virtual :)
  • При разработке в ООП-стиле, объявляет все члены класса как public;
  • Если вам нужно вернуть из функции несколько разных значений (например, результат работы и/или код ошибки), то одно из них возвращает через return, а другое - по указателю или по неконстантной ссылке, вместо использования std::optional, std::pair/std::tuple (особенно хорошо в паре со structured binding) или просто возврата struct;
  • Объявляя новую переменную с типом-структурой, везде пишет struct в имени типа, или наоборот, при объявлении новой структуры пишет typedef struct вместо просто struct;
  • Не использует неймспейсы при структурировании кода;
  • Использует union вместо std::variant (кстати, для каламбура типизации использовать union тоже нельзя, он нарушает active member rule);
  • Пишет реализации общеиспользуемых алгоритмов (foreach, transform, find_if, sort, lower_bound, и т.д.) вручную даже если они есть в <algorithm>;
  • При простой итерации по элементам контейнера пишет многословные конструкции вместо range-based for. Не использует auto и using в многословных конструкциях типов;

Плюс немного дополнений из комментариев:

  • Использует битовые поля вместо std::bitset;
  • Использует си-шные библиотеки на прямую без уровня абстракции над ней;
  • В заголовочных файлах куча инклудов, которые можно было в принципе там и не писать (incomplete class).

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

  • у вас может быть очень много соприкосновений с чисто сишными библиотеками;
  • проект может использовать древний тулчейн, умеющий только C++98 (правда, при работе в таких проектах нужно требовать тройную оплату и дополнительную страховку за вредность, а лучше вообще избегать подобного);
  • вы используете Qt, где своя модель владения, и new там используется на каждом шагу;
  • std::string не подойдет когда вы не можете работать с динамической памятью (хотя, и тут можно придумать что-нибудь интересное с кастомными аллокаторами);
  • абстракции рано или поздно протекают: вы не сможете создать std::fstream из существующего и открытого posix file descriptor (хотя некоторые реализации stdlib такое умеют), а средствами <thread> вы не сможете задать приоритет потоку, и еще много чего;

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

Популярные статьи по теме
Отладочный вывод на микроконтроллерах: как Concepts и Ranges отправили мой printf на покой

Дата: 06 Май 2022

Автор: Гость

Здравствуйте! Меня зовут Александр, и я работаю программистом микроконтроллеров.
Атака Trojan Source для внедрения в код изменений, незаметных для разработчика

Дата: 12 Апр 2022

Автор: Гость

Исследователи из Кембриджского университета опубликовали технику незаметной подстановки вредоносного кода в рецензируемые исходные тексты. Подготовленный метод атаки (CVE-2021-42574) представлен под …
Дизайн и эволюция constexpr в C++

Дата: 13 Янв 2022

Автор: Гость

constexpr - одно из самых магических ключевых слов в современном C++. Оно дает возможность создать код, который будет выполнен еще до окончания процесса компиляции, что является абсолютным пределом д…
C++20: удивить линкер четырьмя строчками кода

Дата: 16 Дек 2021

Автор: Гость

Представьте себе, что вы студент, изучающий современные фичи C++. И вам дали задачу по теме concepts/constraints. У преподавателя, конечно, есть референсное решение "как правильно", но для вас оно не…
C++20 Ranges — Полное руководство

Дата: 07 Дек 2021

Автор: Гость

C++20 Ranges, также известные как STL v2, эффективно заменяют существующие возможности и алгоритмы STL. В этой статье я расскажу вам о нововведениях, которые внесли собой Ranges. Также мы поговорим о…

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

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