1.揭密extern "C"

extern "C"包含双重含义,从字面上即可得到:首先,被它修饰的目标是 "extern”的;其次,被它修饰的目标是 "C”的。
首先来看一下 "extern”的含义
a.在一个文件内,如果外部变量不在文件的开头定义,其有效范围只限定在定义到文件的结束处。如果在定义前需要引用该变量,则要在引用之前用关键字 "extern” 对该变量做“外部变量声明”,表示该变量是一个已经定义的外部变量。有个这个声明,就可以从声明处起合理地使用该变量了。"extern”起到了扩展作用域的作用。

//.c
#include <stdio.h>
void main()
{extern A;//用extern声明外部变量;若变量为int类型,类型名可写也可以省略。printf("%d", A);
}
int A=100;

b.在多文件的程序中,如果多个文件都要使用同一个外部变量,不能在各个文件中各定义一个外部变量,否则会出现“重复定义”的错误。正确的做法是:在任一个文件中定义外部变量,其他文件用 "extern”对变量做“外部变量声明”。在编译和连接时,系统会由此知道该变量是一个已经在别处定义的外部变量,并把另一文件中外部变量的作用域扩展到本文件,这样在本文件就可以合法地使用该外部变量了。

//file1.c
#include <stdio.h>
int A = 100;//定义外部变量
void main()
{printf("%d",power());
}//file2.c
extern A;//声明A为一个已定义的外部变量
int power()
{return A*A;
}

extern只用作声明,而不用于定义。extern说明变量或者函数定义在其他的源文件里,而不用include头文件的方式来引用该函数,在链接时,链接器在各个模块中搜索这个变量或者函数来进行最终链接。
c.外部函数
在定义函数时,如果在最左端加关键字extern,表示此函数是外部函数。C语言规定,如果在定义时省略extern,则隐含为外部函数。而内部函数必须前加static关键字;
在需要调用此函数的文件中,用extern对函数作声明,表示该函数是在其他文件中定义的外部函数。
"C”的含义:(extern “C”)
C++通过函数参数的不同类型支持重载机制,编译器根据参数为每个重载函数产生不同的内部标识符。例如编译器为void Eat(Beef …);void Eat(Fish …);void Eat(Chicken …);三个Eat 函数产生象_eat_beef、_eat_fish、_eat_chicken 之类的内部标识符(不同的编译器可能产生不同风格的内部标识符)。
如果 C++程序要调用已经被编译后的C 函数,该怎么办?
假设某个 C 函数的声明如下:

void foo(int x, int y);

该函数被C 编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,C++程序不能直接调用C 函数。C++提供了一个C连接交换指定符号extern“C”来解决这个问题。
例如:

extern “C”
{
void foo(int x, int y);
… // 其它函数
}
或者写成
extern “C”
{
#include “myheader.h”
… // 其它C 头文件
}

这就告诉C++编译译器,函数foo 是个C 连接,应该到库中找名字_foo 而不是找_foo_int_int。C++编译器开发商已经对C 标准库的头文件作了extern“C”处理,所以我们可以用#include 直接引用这些头文件。

2.extern "C"程序实例

假设有C文件:

//c.h
#ifndef _C_H_
#define _C_H_extern int add(int x, int y);#endif

//c.c
int add(int x, int y)
{return x+y;
}

在C++下调用add()函数

//cplusplus.cpp
#include <iostream>
#include "c.h"
using namespace std;
void main()
{add(1, 0);system("Pause");
}

产生错误:无法解析的外部符号 "int __cdecl add(int,int)" (?add@@YAHHH@Z),该符号在函数 _main 中被引用
为了解决这个问题,我们需要使用extern "C"。改写C文件

//c.h
#ifndef _C_H_
#define _C_H_#ifdef __cplusplus
extern "C" {
#endifextern int add(int x, int y);#ifdef __cplusplus
}
#endif#endif

文件为*.c,__cplusplus没有被定义,extern "C" {}这时没有生效,对于C语言只是extern int add(int, int);而编译c++源文件,__cplusplus被定义,对于C++他看到的是extern "C" {extern int add(int, int);},编译器就会知道add(1, 0)调用的是C连接。
最后:很多DLL的生成文件(XXX.c)中常出现extern "C" ,windows采用C语言编译创建dll,C程序可以正确调用DLL,而当用户使用C++调用DLL时,extern "C" {}就起作用了。

转自:extern "C"的简单解析 - 侯凯 - 博客园
http://www.cnblogs.com/houkai/archive/2013/06/05/3118807.html

转载于:https://www.cnblogs.com/johnleo/p/extern_c.html

externn C解析相关推荐

  1. golang通过RSA算法生成token,go从配置文件中注入密钥文件,go从文件中读取密钥文件,go RSA算法下token生成与解析;go java token共用

    RSA算法 token生成与解析 本文演示两种方式,一种是把密钥文件放在配置文件中,一种是把密钥文件本身放入项目或者容器中. 下面两种的区别在于私钥公钥的初始化, init方法,需要哪种取哪种. 通过 ...

  2. List元素互换,List元素转换下标,Java Collections.swap()方法实例解析

    Java Collections.swap()方法解析 jdk源码: public static void swap(List<?> list, int i, int j) {// ins ...

  3. 条形码?二维码?生成、解析都在这里!

    二维码生成与解析 一.生成二维码 二.解析二维码 三.生成一维码 四.全部的代码 五.pom依赖 直接上代码: 一.生成二维码 public class demo {private static fi ...

  4. Go 学习笔记(82)— Go 第三方库之 viper(解析配置文件、热更新配置文件)

    1. viper 特点 viper 是一个完整的 Go应用程序的配置解决方案,它被设计为在应用程序中工作,并能处理所有类型的配置需求和格式.支持特性功能如下: 设置默认值 读取 JSON.TOML.Y ...

  5. Go 学习笔记(77)— Go 第三方库之 cronexpr(解析 crontab 表达式,定时任务)

    cronexpr 支持的比 Linux 自身的 crontab 更详细,可以精确到秒级别. ​ 1. 实现方式 cronexpr 表达式从前到后的顺序如下所示: 字段类型 是否为必须字段 允许的值 允 ...

  6. mybatis配置文件解析

    mybatis配置文件解析 mybatis核心配置文件`mybatis-config.xml文件. mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息. 能配置的内容: con ...

  7. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

  8. Python 标准库之 xml.etree.ElementTree xml解析

    Python 标准库之 xml.etree.ElementTree Python中有多种xml处理API,常用的有xml.dom.*模块.xml.sax.*模块.xml.parser.expat模块和 ...

  9. 谷歌BERT预训练源码解析(三):训练过程

    目录 前言 源码解析 主函数 自定义模型 遮蔽词预测 下一句预测 规范化数据集 前言 本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BE ...

最新文章

  1. 百度娱乐沸点颁奖典礼,温度太低的“沸点”
  2. mysql clob转string_Java获取Oracle中CLOB字段转换成String
  3. linux抓包提示没有权限,linux下wireshark不用sudo权限抓包包
  4. SpringBoot实战教程(3)| 整合Thymeleaf
  5. GitHub上最火的74个Android开源项目(三)
  6. 个税改革怎么改?媒体称年收入超12万者税负或增加
  7. 【luogu P2319 [HNOI2006]超级英雄】 题解
  8. 9.企业应用架构模式 --- 领域逻辑模式
  9. 基于jQuery的视频和音频播放器jPlayer
  10. 使用spring data JPA进行类目增删改查测试
  11. 针式打印机打印显示传真服务器,针式打印机三联纸怎么设置 点击上面的工具栏上的打印服务...
  12. 【小编教你有效的保护视力】
  13. 「LOJ6198」谢特-SA+可持久化Trie+启发式分裂
  14. 3种性格容易焦虑 你知道吗
  15. 好用的电视盒子软件推荐:无广告看电视我选这两款
  16. java六级_多条件查询----补发周一内容(六级让我忽略了JAVA)
  17. zeus平台常见故障及排查方法
  18. Window端Qt Create dmp的生成与解析
  19. 假设用于通信的电文仅由8个字母组成,字母在电文中出现的频率分别为0.07, 0.19, 0.02, 0.06, 0.32, 0.03, 0.21, 0.10. 试为这8个字母设计赫夫曼编码.
  20. 网站域名历史记录批量查询-老域名建站历史快照数据查询

热门文章

  1. C++ 11 多线程--线程管理
  2. SpringBoot中请求映射的原理(源码)
  3. 排序二叉树BST(binary search/sort tree)
  4. PAT——程序运行时间 (1026)
  5. 汇编语言整数加减法示例
  6. python︱HTML网页解析BeautifulSoup学习笔记
  7. TensorFlow for Hackers - Part III
  8. python enumerate用法_【Python】python enumerate用法总结
  9. 移动端网页打印代码_WEB移动端怎么是实现Console.log打印
  10. set删除一个元素时间复杂度_set/map接口及其实现类