Объединение C++ и C-как работает #ifdef cplusplus?
Я работаю над проектом, который имеет большое наследие C код. Мы начали писать на C++, с намерением в конечном итоге преобразовать унаследованный код. Я немного смущен тем, как C и C++ взаимодействовать. Я понимаю, что, обернув C код extern "C" компилятор C++ не будет калечить C имена кода, но я не совсем уверен, как это реализовать.
Итак, в верхней части каждого C заголовочный файл (после включения ГВ), у нас есть
#ifdef __cplusplus
extern "C" {
#endif
а внизу мы пишем
#ifdef __cplusplus
}
#endif
между ними у нас есть все наши включает, typedefs и прототипы функций. У меня есть несколько вопросов, чтобы увидеть, если я правильно понимаю это:
если у меня есть C++ файл A. hh который
включает в себя C заголовочный файл B. h,
включает в себя еще один C заголовочный файл С. Ч.,
как это работает? Я думаю, что
когда компилятор переходит в B. h,
__cplusplusбудет определен, так что это
обернет код сextern "C"
(и__cplusplusне будет
определено внутри этого блока). Так,
когда он входит в C. h,
__cplusplusне будет определен
и код не будет завернут в
extern "C". Это правильно?что-то не так с
обертывание куска кода с помощью
extern "C" { extern "C" { .. } }?
Что будет второйextern "C"
делать?мы не кладем эту обертку вокруг этот.файлы с, только .H-файлы. Итак, что происходит, если функция не имеет прототипа? Компилятор думает, что это функция C++?
мы также используем некоторые сторонние
код, который написан в C, и
не иметь такого рода обертку вокруг
оно. Каждый раз, когда я включаю заголовок
из той библиотеки, которую я ставил
Анextern "C"вокруг #include.
Это правильный способ справиться
это?наконец, это хорошая идея?
Есть что-нибудь еще, что мы должны сделать?
Мы будем смешивать C и C++
в обозримом будущем, и я
хочу убедиться, что мы покрываем все
наши базы.
3 ответов:
extern "C"на самом деле не меняет способ, которым компилятор читает код. Если ваш код находится в .файл c, он будет скомпилирован как C, если он находится в a .cpp файл, он будет скомпилирован как C++ (если вы не сделаете что-то странное для вашей конфигурации).что
extern "C"это влияет на связь. Функции C++ при компиляции имеют искаженные имена - это то, что делает возможной перегрузку. Название функции изменяется в зависимости от типов и количества параметров, так что два функции с одинаковым именем будут иметь разные названия символов.код внутри
extern "C"по-прежнему C++ код. Есть ограничения на то, что вы можете сделать в блоке extern "C", но все они связаны с привязкой. Вы не можете определить все новые символы, которые не могут быть построены с компоновкой. Это означает, что нет классов или шаблонов, например.
extern "C"блоки красиво гнезда. Там жеextern "C++"если вы окажетесь в безнадежной ловушке внутриextern "C"регионы, но это не такая хорошая идея с точки зрения чистоты.теперь, в частности, относительно ваших пронумерованных вопросов:
относительно #1: __cplusplus должен быть определен внутри
extern "C"блоки. Это не имеет значения, хотя, так как блоки должны гнездиться аккуратно.относительно #2: __cplusplus будет определен для любого блока компиляции, который выполняется через компилятор C++. В общем, это значит .cpp-файлы и любые файлы, включаемые этим .файл cpp. Тот же.ч (или. hh или .hpp или what-have-you) могут быть интерпретированы как C или C++ в разное время, если они включены в разные единицы компиляции. Если вы хотите прототипы в .H файл для ссылки на имена символов C, то они должны иметь
extern "C"при интерпретации как C++, и они не должны иметьextern "C"при интерпретации как C-отсюда#ifdef __cplusplusпроверка.чтобы ответить на ваш вопрос #3: функции без прототипов будут иметь связь C++, если они есть .cpp файлы, а не внутри из ан
extern "C"заблокировать. Это нормально, хотя, потому что если у него нет прототипа, он может быть вызван только другими функциями в том же файле, и тогда вам вообще все равно, как выглядит связь, потому что вы не планируете, чтобы эта функция вызывалась чем-либо вне того же блока компиляции в любом случае.для #4, Вы получили его точно. Если вы включаете заголовок для кода, который имеет связь C (например, код, который был скомпилирован компилятором C), то вы должны
extern "C"заголовок -- таким образом, Вы сможете связаться с библиотекой. (В противном случае ваш компоновщик будет искать функции с именами типа_Z1hicкогда вы искалиvoid h(int, char)5: Этот вид смешивания является распространенной причиной для использования
extern "C"и я не вижу в этом ничего плохого делать это таким образом, просто убедитесь, что вы понимаете, что вы делаете.
extern "C"не изменяет наличие или отсутствие__cplusplusмакрос. Он просто изменяет связь и искажение имен обернутых объявлений.вложения
extern "C"блоки вполне счастливо.если вы скомпилировали
.cфайлы как C++, то ничего неextern "C"блок, и безextern "C"прототип будет рассматриваться как функция C++. Если вы скомпилируете их как C, то, конечно, все будет C функция.да
вы можете безопасно смешивать C и c++ таким образом.
несколько gotchas, которые являются коллорариями к превосходному ответу Андрея Шеланского и немного не согласны с на самом деле не меняет способ, которым компилятор читает код
поскольку ваши прототипы функций компилируются как C, вы не можете перегружать одни и те же имена функций с разными параметрами - это одна из ключевых особенностей искажения имен компилятора. Это описывается как проблема связи, но это не совсем так - вы получите ошибки от компилятора и компоновщика.
ошибки компилятора будут, если вы попытаетесь использовать функции C++ объявления прототипа, такие как перегрузка.
ошибки компоновщика возникнут позже, потому что ваша функция не будет найдена, если вы это сделаете не есть extern "C" обертка вокруг деклараций и заголовка включена в смесь источника C и C++.
одна из причин, чтобы препятствовать людям использовать скомпилировать C как C++ настройка происходит потому, что это означает, что их исходный код больше не переносится. Этот параметр является параметром проекта и поэтому, если a .файл c удаляется в другой проект, он не будет скомпилирован как C++. Я бы предпочел, чтобы люди нашли время, чтобы переименовать суффиксы файлов .СРР.
Comments