О да, это используется. Я работаю в области обработки сетевых пакетов. Я был в двух разных компаниях, где мы обрабатываем сетевые пакеты. Итак, мы работаем на уровне Ethernet или IP, а не на уровне выше TCP.
Интересно, что в обеих компаниях C был выбран над C ++. В одной из компаний один из двух продуктов был построен поверх ядра Linux, тогда как другой продукт был построен в пользовательском пространстве Linux. Продукт ядра, очевидно, использовал C, так как ядро Linux запрограммировано на C, но они решили использовать C и для продукта пользовательского пространства. Оба продукта были разработаны примерно с 2000 года (продукт ядра чуть раньше 2000 года и продукт пользователя чуть позже 2000 года).
В компании, куда я пошел после этого, продукт был построен на C, а не на C ++. Фактически это продолжение проекта середины 1990-х годов, хотя из-за недавних требований к повышению производительности было решено, что по сути все будет переписано. У нас была возможность выбрать C ++ из-за этого переписывания, но мы этого не сделали.
В области обработки сетевых пакетов производительность очень важна. Итак, я хочу реализовать свою собственную хеш-таблицу, имеющую более высокую производительность, чем существующие хеш-таблицы. Я, а не автор хеш-таблицы, выбираю, какую хеш-функцию использовать. Возможно, я хочу производительность и перейти на MurMurHash3 . Возможно, я хочу безопасности и пойти на SipHash . Распределители памяти явно пользовательские. Фактически, все важные структуры данных, которые мы используем, были реализованы на заказ для максимально возможной производительности.
Хотя нет ничего, что могло бы помешать использованию C ++, обычно это плохая идея. Одно выброшенное исключение на пакет снизит скорость обработки пакетов до неприемлемых уровней! Таким образом, мы не можем использовать исключения C ++. Слишком медленно. Мы уже используем своего рода объектно-ориентированный код C, реализуя структуры данных как структуры, а затем реализуя функции, работающие на этих структурах. C ++ позволил бы иметь виртуальные функции, но опять же вызовы виртуальных функций снизили бы производительность, если бы они использовались повсеместно. Итак, лучше быть явным и иметь указатель на функцию, если нужны вызовы виртуальных функций.
C ++ сделает много вещей за вашей спиной: выделение памяти и т. Д. С другой стороны, в C этого обычно не происходит. Вы можете написать функцию, которая выделяет память, но обычно из интерфейса функции видно, что происходит распределение.
В качестве примера микрооптимизации, которую вы можете выполнять при программировании на C, взгляните на макрос container_of в ядре Linux. Конечно, вы можете использовать container_of в коде C ++, но кто это делает? Я имею в виду, что это вполне приемлемо в большинстве программ на C, но типичные программисты на C ++ сразу предложили бы что-то еще, например, связанный список, который выделяет узлы ссылки в виде отдельных блоков. Мы не хотим этого, потому что каждый выделенный блок памяти ухудшает производительность.
Возможно, единственное, что может принести нам пользу в C ++, это то, что C ++ позволяет метапрограммировать шаблоны, то есть вы можете иногда избегать вызовов виртуальных функций, сохраняя при этом параметр функции, и позволяя компилятору встроить функции. Но метапрограммирование шаблонов является сложным, и нам удалось выполнить все требования в C, поэтому преимущество этой функции в C ++ не столь критично.
В одной из компаний у нас фактически был собственный скомпилированный язык, в котором была реализована часть функций. Угадайте, какой язык был целевым для компилятора? Ассамблея? Нет, нам пришлось поддерживать как 32-битные, так и 64-битные архитектуры. C ++? Конечно, ты шутишь. Очевидно, это был C с вычисленным goto GCC . Таким образом, пользовательский язык был скомпилирован в C (или фактически в gcc-варианте C, который поддерживает вычисленное goto), а компилятор C произвел сборку.