extern "C"
на самом деле не меняет способ, которым компилятор читает код. Если ваш код находится в файле .c, он будет скомпилирован как C, если он находится в файле .cpp, он будет скомпилирован как C ++ (если вы не сделаете что-то странное для своей конфигурации).
То, что делает extern "C"
, влияет на связь. Функции C ++ при компиляции имеют искаженные имена - это то, что делает возможной перегрузку. Имя функции изменяется в зависимости от типов и количества параметров, поэтому две функции с одинаковым именем будут иметь разные имена символов.
Код внутри extern "C"
по-прежнему является кодом C ++. Существуют ограничения на то, что вы можете делать в внешнем блоке «C», но все они связаны с сцеплением. Вы не можете определить какие-либо новые символы, которые не могут быть построены с помощью связи C. Это означает, что нет классов или шаблонов, например.
extern "C"
хорошо вписывается в гнездо. Также есть extern "C++"
, если вы окажетесь в безнадежной ловушке внутри extern "C"
регионов, но это не очень хорошая идея с точки зрения чистоты.
Теперь, конкретно по вашим пронумерованным вопросам:
Относительно # 1: __cplusplus останется определенным внутри extern "C"
блоков. Это не имеет значения, так как блоки должны аккуратно вкладываться.
Относительно # 2: __cplusplus будет определен для любого модуля компиляции, который выполняется через компилятор C ++. Как правило, это означает, что файлы .cpp и любые файлы включены в этот файл .cpp. Один и тот же .h (или .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"
, и я не вижу ничего плохого в том, чтобы делать это таким образом - просто убедитесь, что вы понимаете, что делаете.