Я видел эту ссылку, но я не прошу снижения производительности кода, использующего «extern». Я имею в виду без «extern», есть ли «переключение контекста» при использовании библиотеки C в C++? Есть ли какие-либо проблемы при использовании чистых функций C (не обернутых в классы) в приложении C++?
Есть ли снижение/штраф производительности при использовании чистой библиотеки C в коде C++?
Ответы (3)
И C, и C++ являются спецификациями языков программирования (написаны на английском языке, см., например, n1570 для спецификации C11) и говорят не о производительности (а о поведении программы, т.е. о семантика).
Однако вы, скорее всего, будете использовать такой компилятор, как GCC или Clang, которые не приводят к снижению производительности, поскольку создают одно и то же промежуточное внутреннее представление (например, GIMPLE для GCC и LLVM для Clang) как для C, так и для Clang. языки C++, а также поскольку в коде C и C++ используются совместимые ABI и соглашения о вызовах.
На практике extern "C"
не меняет никакого соглашения о вызовах, но отключает изменение имен. Однако его точное влияние на компилятор специфично для этого компилятора. Он может (или нет) отключить встраивание (но рассмотрите -flto
для оптимизации времени компоновки в GCC) .
Некоторые компиляторы C (например, tinycc) создают код с низкой производительностью. Даже GCC или Clang при использовании с -O0
или без явного включения оптимизации (например, путем передачи -O1
или -O2
и т. д...) может производить медленный код (и оптимизации по умолчанию с ним отключены).
Кстати, C++ был разработан для взаимодействия с C (и это сильное ограничение объясняет большинство недостатков C++).
В некоторых случаях подлинный код C++ может быть немного быстрее, чем соответствующий подлинный код C. Например, чтобы отсортировать массив чисел, вы будете использовать std::array и std::sort в подлинном C++, а операции сравнения в сортировке скорее всего, будут встроены. В коде C вы просто используете qsort, и каждое сравнение проходит косвенную вызов функции (поскольку компилятор не встраивает qsort
, даже если теоретически это возможно...).
В некоторых других случаях подлинный код C++ может быть немного медленнее; например, некоторые (но не все) реализации ::operator new
просто вызывают malloc
(затем проверяют на наличие ошибки), но не встроены.
На практике вызов кода C из кода C++ или кода C++ из кода C не вызывает никаких проблем, поскольку соглашения о вызовах совместимы.
Средство C longjmp, вероятно, работает быстрее, чем создание исключений C++, но они не имеют одинаковую семантику (см. раскручивание стека), а longjmp
плохо сочетается между собой код С++.
Если вы так сильно заботитесь о производительности, напишите (на подлинном C и на подлинном C++) вдвое больше кода и теста. Скорее всего, вы заметите небольшую разницу (максимум несколько процентов) между C и C++, поэтому я бы вообще не беспокоился (и ваши опасения по поводу производительности практически неоправданны).
переключение контекста — это концепция, связанная с операционная система и многозадачность и происходит в процессах, запущенных машинный код, исполняемый во время вытеснения. Как этот исполняемый файл получается (из компилятора C, из компилятора C++, из компилятора Go, из компилятора SBCL или быть интерпретатором какого-либо другого языка, такого как Perl или байт-код Python) совершенно не имеет значения (поскольку переключение контекста может произойти в любой компьютерной инструкции во время прерывания). Прочтите несколько книг, например Операционные системы: три простых элемента. .
-fsplit-stack
, чтобы получить одинаковое поведение в коде C и в коде Go, но никто этого не делает.
- person Basile Starynkevitch; 30.12.2017
::operator new
просто вызывают malloc
, но не являются встроенными. Это может быть намного хуже: на моей машине ::operator new()
, реализованная для вызова malloc()
, превосходит стандартную ::operator new()
примерно на сто циклов процессора. за звонок...
- person cmaster - reinstate monica; 30.12.2017
longjmp
может быть быстрее, когда переход/исключение действительно происходит, но механизм генерации исключений C++ почти наверняка быстрее, когда исключения не происходит (т. е. ему не нужен setjmp
и он часто свободен или почти свободен).
- person BeeOnRope; 30.12.2017
На базовом уровне, нет, вы не увидите никакого снижения производительности при "переключении" при вызове библиотеки C из кода C++. Например, вызов из C++ метода C, определенного в другой единице трансляции, должен иметь приблизительно такую же производительность, что и вызов того же метода, реализованного в C++ (таким же образом, как в C) в другой единице трансляции.
Это связано с тем, что распространенные реализации компиляторов C и C++ в конечном итоге компилируют исходный код в машинный код, а вызов функции extern "C"
эффективно поддерживается с использованием того же типа call
, что и для вызова C++. Соглашения о вызовах обычно основаны на платформе ABI и одинаковы в любом случае.
Помимо этого основного факта, при вызове функции C все еще могут быть некоторые недостатки производительности, в отличие от реализации той же функции в C++:
- Функции, реализованные в C и объявленные
extern "C"
и вызываемые из кода C++, обычно не будут встроены (поскольку по определению они не реализованы в заголовке), что препятствует целому ряду, возможно, очень мощной оптимизации0 . - Большинство типов данных, используемых в коде C++1, нельзя напрямую использовать в коде C, поэтому, например, если у вас есть
std::string
в коде C++, вам нужно будет выбрать другой тип для его передачи. в код C -char *
распространен, но теряет информацию о явной длине, что может быть медленнее, чем решение C++. Многие типы не имеют прямого эквивалента в C, поэтому вам может понадобиться дорогостоящее преобразование. - Код C использует
malloc
иfree
для динамического управления памятью, в то время как код C++ обычно используетnew
иdelete
(и обычно предпочитает максимально скрывать эти вызовы за другими классами). Если вам нужно выделить память на одном языке, которая будет освобождена на другом другом, это может привести к несоответствию, когда вам нужно перезвонить на «другой» язык, чтобы освободить, или могут быть ненужные копии и т. д. - В коде C часто интенсивно используются подпрограммы стандартной библиотеки C, а в коде C++ обычно используются методы из стандартной библиотеки C++. Поскольку существует много функциональных совпадений, возможно, что смесь C и C++ занимает больше кода, чем чистый код C++, поскольку используется больше методов библиотеки C2.
Вышеупомянутые опасения применимы только при сравнении реализации на чистом C++ с реализацией на C, и на самом деле не означают, что при вызове C происходит снижение производительности: на самом деле это ответ на вопрос: «Почему можно написать приложение на смеси C и C? С++ медленнее, чем чистый С++?». Кроме того, вышеперечисленные проблемы в основном возникают при очень коротких вызовах, когда вышеуказанные накладные расходы могут быть значительными. Если вы вызываете длинную функцию на C, это не проблема. "Несоответствие типов данных" может по-прежнему кусать вас, но это можно спроектировать на стороне C++.
0 Интересно, что оптимизация времени компоновки фактически позволяет методам C быть встроенными в код C++, что мало упоминаемое преимущество LTO. Конечно, обычно это зависит от самостоятельной сборки библиотеки C из исходного кода с соответствующими параметрами LTO.
1 Например, почти все, кроме стандартного макета.
2 Это, по крайней мере, частично смягчается тем фактом, что многие вызовы стандартной библиотеки C++ в конечном итоге делегируют подпрограммы библиотеки C для «тяжелой» работы, например, как std::copy
вызывает memcpy
или memset
, когда это возможно, и как большинство new
реализации в конечном итоге вызывают malloc
.
C++ вырос и сильно изменился с момента своего создания, но по своей конструкции он обратно совместим с C. Компиляторы C++ обычно строятся на основе компиляторов C, но еще более модернизируются с помощью оптимизация времени компоновки. Я полагаю, что многие программы могут надежно смешивать код C и C++ как в пользовательском пространстве, так и в используемых библиотеках. Недавно я ответил на вопрос, что включает передачу указателя функции-члена класса C++ в библиотечную функцию, реализованную на языке C. Плакат сказал, что это сработало для него. Так что, возможно, C++ более совместим с C, чем думают программисты или пользователи.
Однако C++ работает во многих различных парадигмах, которых нет в C, поскольку он является объектно-ориентированным и реализует целый спектр абстракций, новых типов данных и операторов. Некоторые типы данных легко переводятся (строка char *
C в std::string
), а другие нет. Этот раздел GNU.org о параметрах компилятора C++ может быть какой-то интерес.
Я бы не слишком беспокоился или беспокоился о каком-либо снижении производительности при смешивании двух языков. Конечный пользователь и даже программист вряд ли заметят какие-либо измеримые изменения в производительности, если только они не имеют дело с большими абстракциями данных.
extern "C"
? - person BeeOnRope   schedule 30.12.2017extern "C"
. Функция без оболочки класса является C++. - person   schedule 30.12.2017printf
может быть быстрее, чемcout
из-за отсутствия сложных вызовов иерархии объектов, но может быть медленнее, чемcout
, потому что компилятор C++ уже знает тип переменной и будет вызывать правильную функцию перегрузки напрямую, вместо того, чтобы переходить к функции. для анализа во время выполнения stackoverflow.com/q/2872543/995714 stackoverflow.com/q/3643828/995714 C также не имеет шаблонов, поэтомуqsort
вполне может быть медленнее, чемstd::sort
, поскольку он ничего не знает о вызываемой функции. - person phuclv   schedule 30.12.2017