我们知道,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. 【译】x86程序员手册22-6.4页级保护

    6.4 Page-Level Protection 页级保护 Two kinds of protection are related to pages: 与页相关的保护有两类: Restriction ...

  2. JavaScript判断

    if...else: if...else语句是在指定的条件成立时执行的代码,在条件不成立时执行else后的代码. 语法: if(条件) {条件成立时执行的代码 }else{ 条件不成立的时执行的代码} ...

  3. 【转】非常好的Java反射例子

    转自 http://www.douban.com/note/306848299/ 原文: 1.Java反射的概念 反射含义:可以获取正在运行的Java对象. 2.Java反射的功能 1)可以判断运行时 ...

  4. git常用命令和github

    工作区:就是你的工作目录 暂存区:它像个缓存区域,临时保存你的改动 版本区:就是你的git仓库 HEAD:相当于一个指针,指向你最近一次提交后的结果 git status 查看状态 git add . ...

  5. Win10 “此环境变量太大。此对话框允许将值设置为最长2047个字符。" 解决方法。

    打开注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment 双击右边的 Path (RE ...

  6. 崩溃通常是指操作系统向正在运行的程序发送的信号-EXC_BAD_ACCESS是信号

    https://www.cnblogs.com/feng9exe/p/7243628.html

  7. jmeter插件之PerfMon

    PerfMon是jmeter监控系统资源的一款插件,可以用来监控系统的CPU/内存/IO等性能指标. 一.要准备好的插件:JMeterPlugins-Standard-1.4.0(pwd:cjqd)或 ...

  8. chr()返回值是当前整数对应的 ASCII 字符。

    #chr() 用一个范围在 range(256)内的(就是0-255)整数作参数,返回一个对应的字符.#返回值是当前整数对应的 ASCII 字符.1 import random input_m =10 ...

  9. 关于ORB SLAM2资源整理(持续更新)

    ORB SLAM2源码讲解(吴博) https://www.youtube.com/watch?v=2GVE7FTW7AU 泡泡机器人视频整理: http://space.bilibili.com/3 ...

  10. 虚拟机找不到本机vmnet0,vmnet8,无法连接xshell,解决方案

    首先出现这个问题肯定是第一次下载虚拟机把之前的注册表覆盖了,网卡找不到,首先卸载VMware 并且将C\ProgramData下的VMware文件夹删除掉 ,下载cceaner,点击注册表清除干净,再 ...