Когда использовать extern "C" в С++?

Возможный дубликат:
Зачем нам нужен extern "C" {#include < foo.h > } в С++?

Я часто видел программы, закодированные как:

extern "C" bool doSomeWork() {
  //
  return true;
}

Почему мы используем блок extern "C"? Можем ли мы заменить это чем-то на С++? Есть ли преимущество в использовании extern "C"?

Я вижу ссылку, объясняющую это, но почему нам нужно скомпилировать что-то в C, когда у нас уже есть С++?

Ответ 1

extern "C" делает имена не искаженными.

Используется, когда:

  • Нам нужно использовать некоторую библиотеку C в С++

    extern "C" int foo(int);
    
  • Нам нужно экспортировать код С++ в C

    extern "C" int foo(int) { something; }
    
  • Нам нужна способность разрешать символ в общей библиотеке - поэтому нам нужно избавиться от mangling

    extern "C" int foo(int) { something; }
    ///
    typedef int (*foo_type)(int);
    foo_type f = (foo_type)dlsym(handle,"foo")
    

Ответ 2

Одно место, где extern "C" имеет смысл, - это когда вы связываетесь с библиотекой, которая была скомпилирована как код C.

extern "C" {
  #include "c_only_header.h"
}

В противном случае вы можете получить ошибки компоновщика, потому что библиотека содержит функции с C-linkage (_myfunc), но компилятор С++, который обрабатывал заголовок библиотеки как код на С++, генерировал имена символов С++ для функций ( "_myfunc @XAZZYE" - это называется mangling и отличается для каждого компилятора).

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

extern "C" void __stdcall PrintHello() {
  cout << "Hello World" << endl;
}

Такая функция может быть экспортирована в DLL и затем будет вызываться из другого языка программирования, потому что компилятор не будет калечить свое имя. Если вы добавили еще одну перегрузку той же функции, например.

extern "C" void __stdcall PrintHello() {
  cout << "Hello World" << endl;
}
extern "C" void __stdcall PrintHello(const char *name) {
  cout << "Hello, " << name << endl;
}

Большинство компиляторов затем поймают это и, таким образом, предотвратят использование перегрузок функций в ваших общих функциях DLL.