将外部“C”放入C++代码中具体做什么?

例如:

extern "C" {
   void foo();
}

当前回答

最近,gcc似乎也支持名称篡改。即使在外部“c”中,如果使用类或重载,它也会自动损坏。

#include <stdio.h>
extern "C"{


struct myint{
    int i;
};

struct myint2
{
    int a;
    myint2(int a): a(a) {};
    operator myint() const {return myint{a};}
};

}

void f1(myint i){
    printf("%d", i.i);
}

int main(){
    myint2 a(1);
    f1(a);
}

我甚至使用了许多cpp功能。但代码编译和运行正常。如果你nm,你可以看到main没有损坏,但myint是损坏的。

其他回答

它通知C++编译器在链接时以C样式查找这些函数的名称,因为在链接阶段,用C和C++编译的函数的名称不同。

我之前对dll(动态链接库)文件使用了“extern”C“”,以使etc.main()函数“可导出”,以便稍后可以在dll的另一个可执行文件中使用。也许一个我过去使用它的例子会很有用。

DLL

#include <string.h>
#include <windows.h>

using namespace std;

#define DLL extern "C" __declspec(dllexport)
//I defined DLL for dllexport function
DLL main ()
{
    MessageBox(NULL,"Hi from DLL","DLL",MB_OK);
}

EXE

#include <string.h>
#include <windows.h>

using namespace std;

typedef LPVOID (WINAPI*Function)();//make a placeholder for function from dll
Function mainDLLFunc;//make a variable for function placeholder

int main()
{
    char winDir[MAX_PATH];//will hold path of above dll
    GetCurrentDirectory(sizeof(winDir),winDir);//dll is in same dir as exe
    strcat(winDir,"\\exmple.dll");//concentrate dll name with path
    HINSTANCE DLL = LoadLibrary(winDir);//load example dll
    if(DLL==NULL)
    {
        FreeLibrary((HMODULE)DLL);//if load fails exit
        return 0;
    }
    mainDLLFunc=(Function)GetProcAddress((HMODULE)DLL, "main");
    //defined variable is used to assign a function from dll
    //GetProcAddress is used to locate function with pre defined extern name "DLL"
    //and matcing function name
    if(mainDLLFunc==NULL)
    {
        FreeLibrary((HMODULE)DLL);//if it fails exit
        return 0;
    }
    mainDLLFunc();//run exported function 
    FreeLibrary((HMODULE)DLL);
}

在每个C++程序中,所有非静态函数都在二进制文件中表示为符号。这些符号是唯一标识程序中函数的特殊文本字符串。

在C中,符号名与函数名相同。这是可能的,因为在C中没有两个非静态函数可以具有相同的名称。

因为C++允许重载,并且具有许多C不具备的特性——比如类、成员函数、异常规范——所以不可能简单地使用函数名作为符号名。为了解决这个问题,C++使用了所谓的名称篡改,它将函数名和所有必要的信息(如参数的数量和大小)转换为一些只有编译器和链接器才能处理的奇怪字符串。

因此,如果将函数指定为extern C,编译器不会对其执行名称修改,而是可以直接使用其符号名作为函数名进行访问。

这在使用dlsym()和dlopen()调用此类函数时很方便。

最近,gcc似乎也支持名称篡改。即使在外部“c”中,如果使用类或重载,它也会自动损坏。

#include <stdio.h>
extern "C"{


struct myint{
    int i;
};

struct myint2
{
    int a;
    myint2(int a): a(a) {};
    operator myint() const {return myint{a};}
};

}

void f1(myint i){
    printf("%d", i.i);
}

int main(){
    myint2 a(1);
    f1(a);
}

我甚至使用了许多cpp功能。但代码编译和运行正常。如果你nm,你可以看到main没有损坏,但myint是损坏的。

这个答案是针对那些不耐烦/有最后期限的人的,下面只是部分/简单的解释:

在C++中,您可以通过重载在类中使用相同的名称(例如,由于它们都是相同的名称,因此无法从dll等导出)。解决这些问题的方法是将它们转换为不同的字符串(称为符号),符号说明了函数的名称,也说明了参数,因此即使这些函数具有相同的名称也可以唯一标识(也称为名称损坏)在C中,您没有重载,函数名是唯一的(因此,不需要单独的字符串来唯一标识函数名,因此符号是函数名本身)

所以在C++中,名称mangling唯一标识每个函数在C语言中,即使没有名字,也可以唯一地标识每个函数

要更改C++的行为,即指定不应对特定函数进行名称篡改,可以在函数名称之前使用外部“C”,无论出于何种原因,例如从dll导出具有特定名称的函数,供其客户端使用。

阅读其他答案,了解更详细/更正确的答案。