我们知道,extern关键字可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。这里起到的是声明作用范围的用处。另外,extern还可以与”C”连用,作为链接指示。

一、C++名字修饰(Name Mangling)

这就要从C++的重载说起了,在C++中函数重载指的是几个函数的函数名相同,参数列表不同。那么当生成obj中间文件/目标文件的时候,C++编译器如何区分这几个重载函数呢?——通过把原函数名与参数信息结合,产生一个独特的内部名字,这种技术叫做名字修饰(Name
Mangling)。名字修饰规则没有一个标准,所以不同的编译器的名字修饰规则也不一样。

下面是一组函数,其中f()函数重载了:

int  f (void) { return 1; }
int f (int) { return 0; }
void g (void) { int i = f(), j = f(0); }

f(void)和f(int)是不同的函数,除了函数名相同以外没有任何关系。当生成obj目标文件时,为了区分它们,C++编译器根据参数信息进行了名字修饰:

int  __f_v (void) { return 1; }
int __f_i (int) { return 0; }
void __g_v (void) { int i = __f_v(), j = __f_i(0); }

注意g()也被名字修饰了,虽然没有任何名字冲突。名字修饰应用于C++的任何符号。

二、为什么要使用extern “C”?

C语言中没有名字修饰(Name Mangling),因为C语言不支持函数重载。但是如果C++中含有C代码,在编译时C++编译器对C代码的函数也会进行名字修饰,函数名变了以后,将导致在C运行库中找不到对应函数,发生链接错误。

// 将下面的代码保存为.cpp文件,并用C++编译器编译
int printf(const char *format,...); int main()
{
printf("GeeksforGeeks");
return 0;
}

输出:

/tmp/ccQBO9Im.o:在函数‘main’中:
test.cpp:(.text+0xf):对‘printf(char const*, ...)’未定义的引用
collect2: 错误:ld 返回 1

为了防止C++编译器对C代码进行名字修饰,我们将C代码用extern “C”进行链接指定,告诉编译器,在生成中间文件时,不要对这部分代码进行名字修饰,而是生成符合C规则的中间符号名。

extern "C"
{
int printf(const char *format,...);
} int main()
{
printf("Hello!");
return 0;
}

添加了extern “C”链接指示后,上面的代码就能够正常运行了。

:所有的C风格的头文件(stdio.h, string.h, … 等等)都有在extern “C”下声明,形式如下:

#ifdef __cplusplus
extern "C" {
#endif
/* Declarations of this file */
#ifdef __cplusplus
}
#endif

C++学习之extern "C"的更多相关文章

  1. NSNotification Name 最佳写法

    本文主要借探讨NSNotificationName的最佳写法的机会,学习下extern, static, const, #define 和常量指针与指针常量等的特性和用法. 1.NSNotificat ...

  2. C语言 extern学习2 分析

    上一篇文章中,通过头文件声明,而调用有一个特别大的漏洞: 为什么编译器可以链接过来呢,因为默认是extern修饰的,这种类似全局作用域的功能使其可以被调用 继续加强学习: 这一次有两对C文件: fir ...

  3. 在 C# CLR 中学习 C++ 之了解 extern

    一:背景 在 CLR 源码中有很多的 extern 和 extern "C" 这样的关键词,比如下面这些代码: extern size_t gc_global_mechanisms ...

  4. C语言学习及应用笔记之六:C语言extern关键字及其使用

    在C语言中,修饰符extern用在变量或者函数的声明前,用来以标识变量或者函数的定义在别的文件中,提示编译器遇到此变量或者函数时,在其它文件中寻找其定义.extern关键字的用法有几种,我们下面对其进 ...

  5. C++ Primer 学习笔记与思考_3 ---头文件那些事儿(extern)

    (一)extern在头文件里的使用方法 由于头文件包括在多个源文件里.而且变量的定义仅仅能出现一次,所以在头文件里. 仅仅能够声明不能够出现定义. 我们能够在头文件里用extern声明全局变量,这样在 ...

  6. [C语言学习笔记二] extern 函数的用法

    extern 用来定义一个或多个变量.其后跟数据类型名和初始值.例如: extern int a =10 它与 int,long long int,double,char的本质区别,在于 extern ...

  7. C语言 extern学习1

    没有头文件时,通过本文件内的函数声明来确定定义域,实现功能: //单文件测试 #include <stdio.h> /* 经测试,C语言环境下子函数默认是void型:所以可省略不写 为严谨 ...

  8. [机器学习] 深度学习之caffe1——软件配置与测试

    caffe的编译配置真的是很让人头疼啊,不知道试过多少次了~~~ 重装系统了七八次,搞得linux的一些常用命令倒是很熟悉了~~~ 我有洁癖~~~某一个点上出了错,我一定要把它搞好了,再重新来一次,我 ...

  9. 【NopCommerce源码架构学习-一】--初识高性能的开源商城系统cms

    很多人都说通过阅读.学习大神们高质量的代码是提高自己技术能力最快的方式之一.我觉得通过阅读NopCommerce的源码,可以从中学习很多企业系统.软件开发的规范和一些新的技术.技巧,可以快速地提高我们 ...

随机推荐

  1. bootstrap3无间距栅格/grid no-gutter

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  2. BPI-M1P(全志A20)刷Android启动卡之后启动的过程

    http://blog.csdn.net/wb4916/article/details/78031511BPI-M1P(全志A20)刷Android启动卡之后启动的过程 BPI-M1P(全志A20)刷 ...

  3. 02使用常规步骤编译NanoPiM1Plus的Android4.4.2

    02使用常规步骤编译NanoPiM1Plus的Android4.4.2 大文实验室/大文哥 壹捌陆捌零陆捌捌陆捌贰 21504965 AT qq.com 完成时间:2017/12/5 17:51 版本 ...

  4. Java 基础入门随笔(7) JavaSE版——面向对象定义、特征:封装、构造函数

    面向对象 面向过程:对于面向过程思想,强调的是过程(动作). 面向对象:对于面向对象思想,强调的是对象(实体). 特点: 1,面向对象就是一种常见的思想.符合人们的思考习惯.2,面向对象的出现,将复杂 ...

  5. codeforces_455B

    B. A Lot of Games time limit per test 1 second memory limit per test 256 megabytes input standard in ...

  6. day20-面向对象基础

    目录 面向对象基础 面向过程编程与面向对象编程 面向过程编程 面向对象编程 类与对象 类 对象 定义类和对象 定制对象独有特征 对象属性查找顺序 类与对象的绑定方法 类与数据类型 对象的高度整合 面向 ...

  7. nginx报错:Permission denied

    vi /etc/selinux/config #SELINUX=enforcing #注释掉 #SELINUXTYPE=targeted #注释掉 SELINUX=disabled #增加 :wq! ...

  8. CAD设置背景图片

    把图片作为背景图片可见但是不能编辑操作. 主要用到函数说明: _DMxDrawX::DrawImageToBackground 绘光栅图到背景.详细说明如下: 参数 说明 BSTR sFileName ...

  9. 第一章 React新的前端思维方式

    ---恢复内容开始--- 第一章 React新的前端思维方式 1.1 初始化一个React项目 1.安装create-react-app npm install --global create-rea ...

  10. poj3061 Subsequence【尺取法】

    Description A sequence of N positive integers (10 < N < 100 000), each of them less than or eq ...