Подтвердить что ты не робот

Существует ли снижение производительности/штраф при использовании чистой библиотеки C в коде на С++?

Я видел эту ссылку, но я не прошу о снижении производительности для кода с использованием "extern". Я имею в виду без "extern", есть ли "переключение контекста" при использовании библиотеки C в С++? Есть ли проблемы при использовании чистых C (неклассифицированных) функций в приложении С++?

4b9b3361

Ответ 1

Оба языка C и С++ являются спецификациями языка программирования (см., например, n1570 для спецификации C11) и не говорят о производительности (но о поведении программы, т.е. о semantics).

Однако вы, скорее всего, будете использовать компилятор, такой как GCC или Clang, которые не приносят никакого штрафа за производительность, поскольку он создает такое же промежуточное внутреннее представление (например, GIMPLE для GCC, и LLVM для Clang) для языков C и С++, а потому, что C и Код на С++ совместим с ABI и вызывающие соглашения.

На практике extern "C" не меняют никакого соглашения о вызовах, но отключает name mangling. Однако его точное влияние на компилятор специфично для этого компилятора. Он может (или нет) отключить inlining (но рассмотрите -flto для оптимизации времени соединения в GCC).

Некоторые компиляторы C (например, tinycc) создают код с низкой производительностью. Даже GCC или Clang, когда используется с -O0 или без явного включения оптимизации (например, передача -O1 или -O2 и т.д.) может привести к медленному коду (и оптимизация по умолчанию отключена).

BTW, С++ был разработан для взаимодействия с C (и это сильное ограничение объясняет большую часть недостатков С++).

В некоторых случаях подлинный код на С++ может быть немного быстрее, чем соответствующий подлинный код C. Например, чтобы отсортировать массив чисел, вы будете использовать std:: array и std:: sort в подлинном С++, и операции сравнения в сортировке, скорее всего, будут входить в очередь. С кодом C вы просто используете qsort, и каждое сравнение проходит через косвенный вызов функции (поскольку компилятор не встраивает qsort, даже если теоретически это могло бы...).

В некоторых других случаях подлинный код на С++ может быть немного медленнее; например, несколько (но не все) реализаций ::operator new просто вызывают malloc (затем проверяют на отказ), но не вложены.

На практике не существует штрафа при вызове кода C из кода С++ или кода С++ из кода C, поскольку соглашения о вызовах совместимы.

Объект C longjmp, вероятно, быстрее, чем бросание исключений С++, но они не имеют одинаковой семантики (см. разворачивание стека) и longjmp не очень хорошо сочетается с кодом С++.

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


Контекстный коммутатор - это концепция, относящаяся к multitasking и происходит на процессы работает машинный код, исполняемый во время preemption. Как получается executable (от компилятора C, от компилятора С++, от компилятора Go, от компилятора SBCL или интерпретатор какого-либо другого языка, такого как Perl или байт-код Python) совершенно неактуальен (поскольку контекстный переключатель может произойти при любой машинной инструкции, в течение прерываний). Прочтите несколько книг, таких как Операционные системы: Three Eeasy Pieces.

Ответ 2

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

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

В этом базовом факте могут быть некоторые недостатки производительности при вызове функции C, а не в реализации той же функции в С++:

  • Функции, реализованные в C и объявленные extern "C" и вызываемые из кода С++, обычно не будут встраиваться (поскольку по определению они не реализованы в заголовке), что блокирует целый узел, возможно, очень мощную оптимизацию 0.
  • Большинство типов данных, используемых в коде С++ 1 не могут быть напрямую использованы кодом C, поэтому, например, если у вас есть std::string в вашем коде на С++, вам нужно выбрать другой тип, чтобы передать его в код C - char * является общим, но теряет информацию о явной длине, которая может быть медленнее, чем решение на С++. У многих типов нет прямого эквивалента C, поэтому вы можете столкнуться с дорогостоящим преобразованием.
  • C-код использует malloc и free для управления динамической памятью, в то время как код С++ обычно использует new и delete (и обычно предпочитает как можно больше скрыть эти вызовы за другими классами). Если вам нужно выделить память на одном языке, который будет освобожден другим, это может привести к несоответствию, когда вам нужно перезвонить на "другой" язык, чтобы делать бесплатные или ненужные копии и т.д.
  • C-код часто сильно использует стандартные подпрограммы библиотеки C, в то время как код на С++ обычно использует методы из стандартной библиотеки С++. Так как существует много функционального перекрытия, возможно, что сочетание C и С++ имеет больший размер кода, чем чистый С++-код, так как используются больше C-библиотечных методов 2.

Вышеупомянутые проблемы будут применяться только при сравнении чистой реализации С++ с C и, на самом деле, не означают, что при вызове C происходит ухудшение производительности: на самом деле он отвечает на вопрос "Зачем писать приложение в миксе C и С++ медленнее, чем чистый С++?". Кроме того, вышеупомянутые проблемы в основном связаны с очень короткими вызовами, когда вышеуказанные накладные расходы могут быть значительными. Если вы вызываете длинную функцию в C, это не проблема. "Несоответствие типов данных" все равно может вас укусить, но это может быть спроектировано на стороне С++.


0 Интересно, что оптимизация link-time фактически позволяет C-методам встраивать в код С++, что является незначительным преимуществом LTO. Конечно, это, как правило, зависит от создания библиотеки C из источника с соответствующими параметрами LTO.

1 Например, практически ничего, кроме стандартного типа макета.

2 Это, по крайней мере, частично смягчается тем фактом, что многие стандартные вызовы библиотеки С++ в конечном итоге делегируют подпрограммы библиотеки C для "тяжелого" подъема, например, как std::copy вызывает memcpy или memset, когда это возможно, и как большинство реализаций new в конечном итоге вызывают malloc.

Ответ 3

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

Однако С++ работает во множестве разных парадигм, что C не является, поскольку он объектно-ориентирован, и реализует целый спектр абстракций, новых типов данных и операторов. Некоторые типы данных легко переводимы (char * строка C в std::string), а другие - нет. Этот раздел о GNU.org о параметрах компилятора С++ может представлять определенный интерес.

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