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=;

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

//file1.c
#include <stdio.h>
int A = ;//定义外部变量
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(, );
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" {
#endif extern 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

externn "C"解析的更多相关文章

  1. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  2. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  3. Html Agility Pack 解析Html

    Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面  用Fir ...

  4. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  5. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  6. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  7. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  8. 【知识必备】内存泄漏全解析,从此拒绝ANR,让OOM远离你的身边,跟内存泄漏say byebye

    一.写在前面 对于C++来说,内存泄漏就是new出来的对象没有delete,俗称野指针:而对于java来说,就是new出来的Object放在Heap上无法被GC回收:而这里就把我之前的一篇内存泄漏的总 ...

  9. SQL Server 数据加密功能解析

    SQL Server 数据加密功能解析 转载自: 腾云阁 https://www.qcloud.com/community/article/194 数据加密是数据库被破解.物理介质被盗.备份被窃取的最 ...

随机推荐

  1. base64自定义编码表 php版本

    在一次接口对接中,要用到base64自定义编码表来进行编码和解码,从网上搜索了一下,讲原理的比较多也比较透彻,提供的编码的例子但是没有解码的,以下是自己实现的一个base64自定义字典解码的例子,比较 ...

  2. 【04】基础:将采集结果转成Excel

    前面的教程说了,数据抓取完毕之后,数据以xml格式的形式存储在本地文件夹中. 下面简单地说一下如何将保存在本地的XML文件转成Excel格式. 第一步:压缩文件 进入本地DataScraperWork ...

  3. Can you find it?(hdu 2141 二分查找)

    Can you find it? Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/10000 K (Java/Others ...

  4. 镜像树(dfs)

    1214: J.镜像树 时间限制: 1 Sec  内存限制: 64 MB提交: 18  解决: 7 标签提交统计讨论版 题目描述 一棵二叉树,若其与自己的镜像完全相同,就称其为镜像树(即这棵二叉树关于 ...

  5. 常见的SQL字符串函数

    1.LEN:计算字符串的长度(字符的个数) select len('哈哈hello') 返回长度为7 2.datalength();计算字符串所占用的字节数,不属于字符串函数 select DATAL ...

  6. TEA encryption with 128bit key

    If anyone needs some basic encryption in software, here's one solution. This TEA implementation fits ...

  7. qsort排序算法

      七种qsort排序方法 <本文中排序都是采用的从小到大排序> 一.对int类型数组排序 int num[100]; Sample: int cmp ( const void *a ,  ...

  8. Unique Binary Search Trees II 解答

    Question Given n, generate all structurally unique BST's (binary search trees) that store values 1.. ...

  9. Windows多线程同步系列之一-----互斥对象

    多线程同步之互斥对象 作者:vpoet mail:vpoet_sir@163.com   对卖票问题进行线程间同步,本文将在上文的基础上,使用互斥对象对线程进行同步. 首先看看windows API ...

  10. Spring-Junit4

      Spring整合Junit4测试Service 1. 加入依赖包 使用Spring的测试框架需要加入以下依赖包: JUnit 4 (官方下载:https://github.com/KentBeck ...