Почему драйверы и встроенные микропрограммные обеспечения почти всегда пишутся в C или ASM и не C++?

Мне просто любопытно, почему драйверы и встроенные микропрограммные обеспечения почти всегда пишутся в C или блоке и не C++?

Я услышал, что существует техническая причина этого.

Кто-либо знает это?

Большая любовь, Louise

45
задан Louise 11 January 2010 в 01:34
поделиться

15 ответов

Поскольку, в большинстве случаев операционная система (или «библиотека времени выполнения») обеспечивает функциональность STDLIB, необходимой C ++.

В C и ASM вы можете создавать голые исполняемые файлы, которые не содержат внешних зависимостей.

Однако, поскольку Windows поддерживает C ++ STDLIB, большинство драйверов Windows записываются в (ограниченное подмножество) C ++.

Также, когда прошивка написана ASM, это обычно потому, что либо (a) платформа выполняется, не имеет компилятора C ++, либо (b) существуют экстремальные ограничения скорости или размера.

Обратите внимание, что (B) обычно не было проблемой с начала 2000-х годов.

31
ответ дан 26 November 2019 в 21:01
поделиться

Существует много стилей программирования, таких как процедурный, функциональный, ориентирован на объект и т. Д. Программирование объектно-ориентированного объекта, более подходит для моделирования реального мира.

Я бы использовал объектно-ориентированные для драйверов устройств, если он это подходит. Но, большую часть времени, когда вы программируете драйверы устройства, вам не понадобятся преимущества, предоставляемые C ++, такие как, абстракция, полиморфизм, повторное использование кода и т. Д.

1
ответ дан 26 November 2019 в 21:01
поделиться

Когда запрос обслуживается php, «очищает» экземпляр и освобождает ресурсы и другие переменные. Это делается в несколько этапов. Поскольку fastcgi сохраняет процесс после запроса, не все шаги выполняются и не вся память освобождается. Существует, например, EG (persistent_list), который используется mysql _ pconnect () , pg _ pconnect () ,... Этот список не освобождается между запросами, пока процесс остается в живых (может быть, в зависимости от фактической реализации, но это будет противоречить цели EG (persistent_list)). Если используются постоянные подключения, сценарий может получить «повторно используемое» подключение, установленное во время предыдущего запроса.
Чтобы (повторно) использовать подготовленную инструкцию непосредственно, необходим идентификатор этой инструкции (и этого соединения). При использовании (php-) postgresql это просто (по соединениям) уникальная последовательность, которую вы передаете в pg _ execute () , поэтому у вашего сценария нет проблем с получением доступа к инструкции, ранее подготовленной другим экземпляром (с использованием того же соединения).
При использовании mysqli или PDO-mysql в качестве идентификатора оператора необходим ресурс/объект. Это своего рода проблема, так как ни mysqli, ни pdo расширение, кажется, не предлагает способ хранения ресурса в EG (persist_list) между запросами, и вы не можете воссоздать его. Если php-fpm не предлагает такую «услугу», кажется невозможным повторно использовать mysql подготовленный оператор напрямую.
Все, на что вы можете надеяться, это кэш запросов на стороне сервера MySQL . В последних версиях (см. ссылку) он может распознавать оператор при использовании подготовленных операторов. Но даже тогда он не будет повторно использовать фактический подготовленный оператор:

Для подготовленного оператора, выполненного по двоичному протоколу, сравнение с операторами в кэше запросов основано на тексте оператора после расширения? маркеры параметров . Оператор сравнивается только с другими кэшированными операторами, выполненными через двоичный протокол. То есть для целей кэша запросов операторы, выдаваемые через двоичный протокол, отличаются от операторов, выдаваемых через текстовый протокол.

Таким образом, если я не ошибаюсь, в настоящее время вы не можете повторно использовать mysql утверждение, подготовленное во время предыдущего запроса в php.

-121--2404225-

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

#include <stdio.h>

#define OS_VER   5.10
#define DRIVER_VER "1.2.3"

int drivermain(driverstructinfo **dsi){
   if ((*dsi)->version > OS_VER){
       (*dsi)->InitDriver();
       printf("FooBar Driver Loaded\n");
       printf("Version: %s", DRIVER_VER);
       (*dsi)->Dispatch = fooDispatch;
   }else{
       (*dsi)->Exit(0);
   }
}

void fooDispatch(driverstructinfo *dsi){
   printf("Dispatched %d\n", dsi->GetDispatchId());
}

Обратите внимание, что поддержка библиотеки времени выполнения должна быть втянута и связана во время компиляции/ссылки, он бы не работал как среда выполнения (то есть, когда операционная система находится во время фазы загрузки/инициализации) не полностью настроен, и, следовательно, не было бы никаких подсказок о том, как printf , и, вероятно, звучал бы смертельный удар операционной системы (паника ядра для Linux, синий экран для Windows), так как нет ссылок на то, как выполнять функцию.

Поставьте другой способ, с водителем,этот код драйвера имеет привилегии для выполнения кода вместе с кодом ядра, который будет совместно использовать одно и то же пространство, ring0 является конечной привилегией выполнения кода (все инструкции разрешены), вызывать3 - это место, в котором работает внешний интерфейс операционной системы. (ограниченная привилегия выполнения), другими словами, код ring3 не может иметь команду, которая зарезервирована для ring0, ядро уничтожит код, треппируя его так, как если бы он сказал «Эй, у вас нет привилегии обрабатывать домен ring0».

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

Большинство драйверов устройств (в случае Windows) имеют специальную цепочку инструментов компилятора ( WinDDK ), которая может использовать код Си, но не имеет связи с обычными стандартными библиотеками времени выполнения Си.

Существует один набор средств, позволяющий создать драйвер в Visual Studio, StartDDK . Во всяком случае, построение драйвера не для слабонервных, вы получите стресс-индуцированную активность, глядя на голубые экраны, ядро паники и интересно, почему, отладка драйверов и так далее.

Отладочная сторона труднее, код ring0 труднодоступен по коду ring3, так как двери на нее закрыты, это через дверцу ловушки ядра (для желания лучшего слова) и если спрашивают вежливо, дверь все еще остается закрытой, в то время как ядро делегирует задачу обработчику, находящемуся на ринг0, выполнить его, независимо от возвращаемых результатов, передаются обратно в код ринг3, и дверь все еще остается закрытой. Это аналогическая концепция того, как код пользователя может выполнять привилегированный код в вызывном сигнале 0.

Кроме того, этот привилегированный код может легко попирать пространство памяти ядра и повредить что-то, следовательно, ядро паники/bluescreens...

Надеюсь, это поможет.

-121--1111710-

, поскольку с системного уровня драйверы должны управлять всеми битами каждого байта памяти, другой более высокий язык не может это сделать, или не может сделать это, только C/Asm достичь ~

0
ответ дан 26 November 2019 в 21:01
поделиться

Драйверы для Windows написаны на C++.
Драйверы Linux написаны на c, так как ядро написано на c.

.
4
ответ дан 26 November 2019 в 21:01
поделиться

Вероятно, потому, что c все еще часто бывает быстрее, меньше при компиляции, и более последовательна при компиляции между разными версиями ОС, и с меньшим количеством зависимостей. Также, так как c++ действительно построен на c, вопрос в том, нужно ли вам то, что он предоставляет?

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

1
ответ дан 26 November 2019 в 21:01
поделиться

C очень близок к машинному независимому языку ассемблера. Большая часть программирования типа ОС находится на уровне "голого металла". В языке Си читаемый вами код является реальным кодом. Си++ может скрывать то, что Си не может.

Это только мое мнение, но я потратил много времени в своей жизни на драйверы отладочных устройств и вещи, связанные с ОС. Часто смотря на ассемблерный язык. Держите его простым на низком уровне и дайте уровню приложения прийти в воображение.

5
ответ дан 26 November 2019 в 21:01
поделиться

За исключением более широкой поддержки инструментов и переносимости оборудования, я не думаю, что есть веская причина ограничивать себя C. Я часто вижу сложные ручные кодировки, которые более естественно делать на Си++:

  • Группировка в "модули" функций (не общего назначения), которые работают только на одной и той же структуре данных (часто называемых "объектами") -> Использовать С++ классы.
  • Использование указателя "handle" для того, чтобы функции модуля могли работать с "экземплярами" структур данных -> использовать С++ классы.
  • Использование функциональноподобных макросов -> C++ шаблонов и inline-функций
  • Различное поведение во время выполнения в зависимости от идентификатора типа, либо с помощью ручного vtable ("дескриптора"), либо с помощью оператора switch statement -> C++ полиморфизм
  • Арифметика с указателями на ошибки для сортировки/демарширования данных из/в коммуникационный порт, либо использование непортативных структур -> концепция потока C++ (не обязательно std::iostream)
  • Префиксация ада из всего, чтобы избежать столкновения имен: Пространства имен C++

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

Конечно, вы можете быть не в состоянии использовать STL либерально (или вообще) в ограниченном окружении, но это не означает, что вы не можете использовать C++ как "лучший C".

10
ответ дан 26 November 2019 в 21:01
поделиться

1) "Потому что так было всегда" - это на самом деле объясняет больше, чем вы думаете - учитывая, что API практически на всех современных системах изначально были написаны на C или ASM, и учитывая, что много предшествующего кода существует на C и ASM, часто проще "идти по потоку", чем выяснять, как воспользоваться преимуществами C++.

2) Окружение - для использования всех возможностей Си++ требуется довольно специфическое окружение исполнения, часть из которых просто неудобно предоставлять драйверу. Это проще сделать, если Вы ограничиваете свой набор возможностей, но кроме всего прочего, управление памятью может стать очень интересным в C++, если у Вас не так много кучи. Исключения также очень интересны в этой среде, как и RTTI.

3) "Я не вижу, что она делает". Любой достаточно опытный программист может посмотреть на строку Си и иметь хорошее представление о том, что происходит на уровне машинного кода, чтобы реализовать эту строку. Очевидно, что оптимизация это несколько меняет, но по большей части можно сказать, что происходит. В Си++, учитывая перегрузку оператора, конструкторы, деструкторы, исключения и т.д., становится действительно сложно иметь представление о том, что произойдет в данной строке кода. При написании драйверов устройств это может быть смертельно, так как часто вы ДОЛЖНЫ знать, собираетесь ли вы взаимодействовать с менеджером памяти, или же строка кода влияет (или зависит от) уровней прерываний или маскировки.

Вполне возможно писать драйверы устройств под Windows, используя C++ - я сделал это сам. Предупреждение в том, что нужно быть осторожным в том, какие возможности С++ вы используете и откуда.

11
ответ дан 26 November 2019 в 21:01
поделиться

Возможно, поскольку водитель не требует объектных ориентированных объектов, в то время как тот факт, что C все еще имеет несколько зрелых компиляторов, будет иметь значение.

1
ответ дан 26 November 2019 в 21:01
поделиться

Комментарии, к которым я столкнулся, так как магазин использует C для встроенной системы по сравнению с C ++:

  1. C ++ производит код Bloat
  2. С ++ исключения комната.
  3. полиморфизм C ++ и виртуальные таблицы Используйте слишком много памяти или выполнения время.
  4. Люди в магазине не знают язык C ++.

Единственная действительная причина может быть последней. Я видел языковые программы, которые включают OOP, функциональные объекты и виртуальные функции. Это очень уродливо очень быстро и блуждает код.

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

Причина, по которой я предпочитаю C ++ к C в встраиваемых системах, заключается в том, что C ++ является сильным типом языком. Больше вопросов можно найти в компиляционном времени, что снижает время разработки. Кроме того, C ++ является более легким языком для реализации объектных концепций, чем C.

Большинство причин против C ++ - вокруг концепций дизайна, а не фактический язык.

7
ответ дан 26 November 2019 в 21:01
поделиться

Причина, которую используется C, не C ++, не является:

  • , потому что C ++ медленнее
  • или потому, что C-Runtime уже присутствует.

Это потому, что C ++ использует исключения. Большинство реализаций языковых исключений C ++ непригодны в коде драйвера, поскольку драйверы вызываются, когда ОС отвечает на аппаратные прерывания. Во время прерывания аппаратного обеспечения код драйвера не разрешается использовать исключения, так как бы / могло бы вызвать рекурсивные прерывания. Кроме того, пространство стека, доступное для кода, в то время как в контексте прерывания, как правило, очень маленький (и не вырабатывается как следствие правила исключения нет).

Вы можете, конечно, использовать новые (std :: nothrow), но потому что исключения в C ++ теперь Ubiqutious, это означает, что вы не можете полагаться на любой библиотечный код для использования STD :: Nothrow Semantics.

Это также потому, что C ++ отказался от нескольких особенностей C: - В водителях важно размещение кода. Драйверы устройств должны быть в состоянии реагировать на прерывания. Код прерывания должен быть размещен в сегментах кода, которые являются «не вкладываемыми» или навсегда отображаются в память, так как, если код был в памяти в магистрате, он может быть выпущен при вызове, что вызовет исключение, которое заблокировано. В C компиляторов, которые используются для разработки драйверов, есть директивы #PRAGMA, которые могут контролировать, какой тип функций памяти в конечном итоге. В качестве негруппированного пула является очень ограниченным ресурсом, вы не хотите пометить весь свой драйвер как не вступить: C ++, однако, генерирует много неявного кода. Например, конструкторы по умолчанию. Нет никакого способа кронштейна C ++, неявно сгенерированный код для управления его размещением, и поскольку операторы преобразования автоматически вызываются, нет способа аудита кода, чтобы гарантировать, что нет побочных эффектов, вызывающих в Costed код.

Итак, для суммирования: - Причина C, а не C ++ используется для разработки драйверов, заключается в том, что драйверы, записанные на C ++, будут либо потребляют необоснованные количества памяти не загадочной, либо сбой ядра ОС.

7
ответ дан 26 November 2019 в 21:01
поделиться

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

C++ может использоваться , но только в том случае, если время выполнения специально приспособлено для обращения только к внутренним таблицам в фиксированной памяти (не страничной), когда механизм выполнения вызывается неявно, например, с помощью vtable при вызове виртуальных функций. Эта специальная адаптация в большинстве случаев не выходит "из коробки".

Интегрировать С с платформой гораздо проще, так как легко лишить С стандартной библиотеки и сохранить контроль над доступом к памяти предельно явным. Так что, будучи известным языком, он часто является выбором дизайнеров инструментов ядра.

Правка : Удалена ссылка на новые и удалённые вызовы (это было неправильно/неудалённо); заменена более общей фразой "run-time machinery".

7
ответ дан 26 November 2019 в 21:01
поделиться

Код в ядре выполняется в совершенно другом окружении, чем в пользовательском пространстве. Разделения процессов нет, так что ошибки гораздо сложнее восстановить; об исключениях не может быть и речи. Существуют различные аллокаторы памяти, поэтому может быть сложнее получить новый и удалить для корректной работы в контексте ядра. Доступно меньше стандартной библиотеки, что значительно усложняет эффективное использование языка типа Си++.

Windows позволяет использовать очень ограниченное подмножество языка Си++ в драйверах ядра; по сути, те вещи, которые могут быть тривиально переведены на Си, такие как объявления переменных в местах помимо начала блоков. Они рекомендуют не использовать new и delete, и не имеют поддержки RTTI или большинства стандартных библиотек C++.

Mac OS X использует I/O Kit, который представляет собой фреймворк, основанный на ограниченном подмножестве C++, хотя, насколько я могу судить, более полный, чем это разрешено в Windows. По сути, это C++ без исключений и RTTI.

Большинство Unix-подобных операционных систем (Linux, BSD) написаны на C, и я думаю, что никто никогда не видел пользы от добавления поддержки C++ в ядро, учитывая, что C++ в ядре обычно так ограничен.

26
ответ дан 26 November 2019 в 21:01
поделиться

Вот способ обработки « Ruby-esque »:

temp _ array = Marshal.load (Marshal.dump (your_array_to_be_cloned))

-121--167777-

Единственный верный ответ: это зависит от .

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

Общая идея заключается в том, что если версия < 5,1,17, подготовленная инструкция никогда не кэшируется в кэше запроса, а если используется > = 5,1,17, это зависит от .

См. следующую страницу в руководстве MySQL 5,1:

http://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html

-121--2404228-

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

#include <stdio.h>

#define OS_VER   5.10
#define DRIVER_VER "1.2.3"

int drivermain(driverstructinfo **dsi){
   if ((*dsi)->version > OS_VER){
       (*dsi)->InitDriver();
       printf("FooBar Driver Loaded\n");
       printf("Version: %s", DRIVER_VER);
       (*dsi)->Dispatch = fooDispatch;
   }else{
       (*dsi)->Exit(0);
   }
}

void fooDispatch(driverstructinfo *dsi){
   printf("Dispatched %d\n", dsi->GetDispatchId());
}

Обратите внимание, что поддержка библиотеки времени выполнения должна быть включена и связана во время компиляции/ссылки, это не будет работать как среда выполнения (то есть, когда операционная система находится во время фазы загрузки/инициализации) не полностью настроен, и, следовательно, не было бы никаких подсказок о том, как printf , и, вероятно, звучал бы смертельный удар операционной системы (паника ядра для Linux, синий экран для Windows), так как нет ссылок на то, как выполнять функцию.

Поставьте другому пути, с драйвером, что код драйвера имеет привилегии для выполнения кода вместе с кодом ядра, который будет совместно использовать то же пространство, ring0 является конечной привилегией выполнения кода (все инструкции разрешены), вызывать3 - это место, в котором работает внешний интерфейс операционной системы. (ограниченная привилегия выполнения), другими словами, код ring3 не может иметь команду, которая зарезервирована для ring0, ядро уничтожит код, треппируя его так, как если бы он сказал «Эй, у вас нет привилегии обрабатывать домен ring0».

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

Большинство драйверов устройств (в случае Windows) имеют специальную цепочку инструментов компилятора ( WinDDK ), которая может использовать код Си, но не имеет связи с обычными стандартными библиотеками времени выполнения Си.

Существует один набор средств, позволяющий создать драйвер в Visual Studio, StartDDK . Во всяком случае, построение драйвера не для слабонервных, вы получите стресс-индуцированную активность, глядя на голубые экраны, ядро паники и интересно, почему, отладка драйверов и так далее.

Отладочная сторона труднее, код ring0 не легко доступен по коду звонка3, так как двери в нее закрыты, это через дверцу ловушки ядра (по желанию лучшего слова) и, если спросить вежливо, дверь все еще остается закрытой, в то время как ядро делегирует задачу обработчику, находящемуся на звонке0, выполнить его,какие бы результаты ни были возвращены, они передаются обратно в код звонка3, и дверь все еще остается закрытой. Это аналогическая концепция того, как код пользователя может выполнять привилегированный код в вызывном сигнале 0.

Кроме того, этот привилегированный код может легко попирать пространство памяти ядра и повредить что-то, следовательно, ядро паники/bluescreens...

Надеюсь, это поможет.

2
ответ дан 26 November 2019 в 21:01
поделиться

Ну, драйверы Iokit для MacOSX , написанные в подмножестве C ++ (без исключения, шаблонов, многократных наследств). И есть даже возможность писать модули ядра Linux в Haskell.)

В противном случае C, являющийся портативным языком сборки, идеально уловившись в области архитектуры и вычислительной архитектуры Von Neumann, что позволяет для прямого контроля над всеми особенностями и недостатками (такими Как «узкое место в Неймане»). C имеет значение именно то, что он был разработан и ловит свою целевую модель абстракции полностью и безупречно (хорошо, за исключением неявного предположения в едином контрольном потоке, который мог бы быть обобщенным для покрытия реальности аппаратных нитей), и поэтому я думаю, что это красивая Язык.) Ограничение выразительной мощности языка для таких основ устраняет большинство непредсказуемых деталей преобразования, когда к этому де-фактическому стандарту применяется разные вычислительные модели. Другими словами, C делает вас придерживаться оснований и позволяет в значительной степени прямой контроль над тем, что вы делаете, например, при моделировании поведения общности с виртуальными функциями, которые вы контролируете, как именно столы указателей функции хранятся и используются при сравнении с неявным распределением VTBL C ++ и управление. Это на самом деле полезно при рассмотрении кэшей.

Сказав, что объектная парадигма очень полезна для представления физических объектов и их зависимостей. Добавление наследства мы получаем объектно-ориентированную парадигму, которая, в свою очередь, очень полезна для представления структуры и иерархии поведения физических объектов. Ничто не останавливает никого из него, и выражая его в C снова, позволяя полностью контролировать, как именно ваши объекты будут созданы, сохранены, уничтожены и скопированы. На самом деле, это подход, взятый в модели устройства Linux. Они получили «объекты» для представления устройств, иерархии реализации объекта для моделирования зависимости управления питанием и функциональностью взломанного наследования для представления семейств устройства, все, что сделано в C.

1
ответ дан 26 November 2019 в 21:01
поделиться