在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?

一、extern简介

首先我们用一句话来形容extern的作用:解决名字匹配问题,实现C/C++混合编程。

extern是C/C++语言表明函数和全局变量作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用。

通常我们在模块的头文件中对本模块提供给其他模块引用的函数或全局变量用关键字extern声明。被extern “C”修饰的变量和函数是按照C语言方式编译和连接的。

C++是一种面向对象的语言,它支持了函数的重载,而C语言是一种面向过程式的语言,它并不支持函数的重载。

例:
一个函数原型为void foo(int x, int y );该函数被C语言编译器编译后名字变为_foo,而在C++编译器中被编译为_foo_int_int之类的名字(不同的编译器可能产生不同的名字),它包含了函数名称,参数数量以及参数类型,C++也是因此而支持函数的重载。

二、举例说明

环境:vs2015
假设一个工程里面有一个test1.c文件和一个test2.cpp文件。

(一)在C++文件中用extern声明函数

  • text1.c
int foo(int x, int y)
{
    return x + y;
}
  • test2.cpp
#include 
extern int foo(int x, int y);
using namespace std;
int main()
{
    cout << foo(1, 2) << endl;
    return 0;
}

此时运行编译器会给出如下提示:

这里写图片描述

解答:

由于C语言和C++程序在编译时,是相互独立编译的;在.c文件中foo函数被命名为_foo;而在.cpp文件内编译器将用extern声明的函数重命名为(?foo@@YAHHH@Z)。
在链接阶段,在_main函数中foo函数被调用,此时编译器带着(?foo@@YAHHH@Z)函数名进入test1.c文件的编译文件中去找(?foo@@YAHHH@Z)函数,但是在test11c文件中foo函数被编译器重新命名后并不是这个名字,所以我们在.cpp文件中声明的外部函数找不到真正定义的地方,所以程序错误。

(二)在C++文件中用extern “C”声明函数

注意此处的c是大写!

一但当我们用小写的时候,编译器就会给出这样的错误:

在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?_第1张图片

所以此处我们需要用大写,正确格式如下:

extern "C" int foo(int x, int y);
  • test1.c
int foo(int x, int y)
{
    return x + y;
}
  • test2.cpp
#include 
extern "C" int foo(int x, int y);
using namespace std;
int main()
{
    cout << foo(1, 2) << endl;
    return 0;
}

解答:

C++为了支持函数的重载,对编译时函数的重名规则进行更改,使用extern “C”的方式在C++程序中声明的C语言文件中的函数,可以在编译时,告诉编译器使用C语言的规则对该函数的函数名进行重命名,这样在链接的时候,就可以顺利的在.c文件中找到该函数。

你可能感兴趣的:(C++,C/C++之路)