今天上课实在无聊,就看了看 extern "C" 的作用,看了以后对它有了一点点理解,在这里给大家分享一下(本菜鸡水平有限,如若有说得不对的地方,还望大家指出)。

extern 关键字:

  首先还是先看一下 extern 关键字的作用:extern关键字可以置于变量或函数前,以标示变量或函数的定义在别的文件中,提示编译器遇到此变量或函数时在其他模块中寻找其定义。

  通常情况下,比如我们在头文件  "b.h"  中声明了一个函数,然后在 "b.cpp" 中实现了该函数,当在 "main.cpp" 中调用 "b.h" 中声明的函数时,只需要在 ""main.cpp" 中 #include "b.h" 就可以了。例子如下:

//b.h

#pragma once
#include <iostream> using namespace std; void test();
//b.cpp

#include "b.h"

void test()
{
cout << "hello world" << endl;
}
//main.cpp
#include "b.h" int main()
{
test();
system("pause");
return ;
}

  除了通过 #include "b.h" 这样的方式能调用到 "b.h" 中的函数外,还有下面这种方式也能调用到"b.h" 的函数。

//main.cpp

//#include "b.h" //在这里,不注释掉也是可以得,但是在对于 变量 来说时就必须注释掉了
#include <iostream>
using namespace std; extern void test();//告诉编译器test()函数声明在其他文件中 int main()
{
test();
system("pause");
return ;
}

  上面是对于函数而言,那么要是在 "b.h" 中定义了一个全局变量 int x,(记住是全局变量哦!)现在我们想在 "main.cpp" 中访问变量 x, 那该怎么办呢? 会不会 #include "b.h" 后就可以直接访问了呢?我们先试一下:

//b.h

#pragma once
#include <iostream> using namespace std; int x = ; void test();
//main.cpp
#include "b.h" int main()
{
cout << "x=" << x << endl;
system("pause");
return ;
}

  我们在 "main.cpp" 中输出变量 x, 此时编译时没有问题的,但是当运行时,它就会报错:fatal error LNK1169: 找到一个或多个多重定义的符号。  通过 #include "b.h" 这种方式就想访问到变量 x 太天真了,是访问不到的,因为 "b.h" 的全局变量 x 的访问作用域是文件作用域,它只能在 "b.h" 这个文件中进访问,记住是只能在 "b.h" 中进行访问,在 "b.cpp"中通过 #include "b.h" 你也是不能访问的。 那么现在我们有没有其他方式能在 "main.cpp" 中访问到变量 x 呢?当然有,通过 "extern" 关键字能达到目的。用法如下:

//main.cpp
//#include "b.h" //一定要注释掉
#include <iostream> using namespace std; extern int x; int main()
{
cout << "x=" << x << endl;
system("pause");
return ;
}

  说了那么多废话,终于把 extern 关键字说清楚了。(我想我是说清楚了,嘿嘿嘿), 接下来这个才是今天的狠角色。

extern "C"

  要说清楚 extern "C" 是怎么一回事,还得先说说C++函数重载的那些事。C++有函数重载,而C语言是没有函数重载的。函数重载是指两个或多个函数之间函数名相同,参数列表不同,参数列表不同可以是参数的个数不同,或者是参数的个数相同但参数类型不同,需要注意的是如果函数名相同,参数列表完全相同但返回值类型不同是不能构成函数重载的。C++有函数重载是因为当生成obj中间文件/目标文件的时候,C++编译器把原函数名与参数信息结合,产生了一个独特的内部名字,比如有两个函数 void foo(int x) 和 void foo(void) ,最终产生的内部名字就是 _foo_int 和 _foo_void (实际产生的内部名字的命名规则应该不是这样的,这里我们并不关心它的命名规则是怎样的,只需要体会这个意思就可以了),通过这样编译器就能区分 void foo(int x) 和 void foo(void)这两个函数了。但是在C语言里面,并不会产生这样的内部名字,如果C语言里面有两个函数 void foo(int x) 和void foo(void),那么当生成obj中间文件/目标文件的时候,产生的名字就是 _foo 和 _foo 这样两个名字相同,C编译器就不能将两个函数区分开了,所以C语言里面也就没了函数重载。

  正是由于C++编译器 和 C编译器对函数名处理方式的不同,当我们的 C++ 程序调用 C 程序或者 C 程序调用 C++程序时就会存在问题。 有了问题那当然就得解决,于是就有了 extern "C" 的出现。

  所以说到底 extern "C" 的作用是用来解决名字匹配问题,实现 C 与 C++ 的混合编程。摆这么一句话在这里显得很苍白无力,还是举例说明一下。

C++ 调用 C 语言函数:

//a.h
#include <stdio.h> void test(int x, double y);
//a.c
#include "a.h" void test(int x, double y)
{
printf("hello world\n");
}

  上面的test函数是 C 语言实现的,我们在 "main.cpp" 进行调用,首先通过如下方式进行调用:

//main.cpp

#include "a.h"

int main()
{
test(,1.2);
getchar();
return ;
}

  通过上面这种方式调用,编译能通过,但是运行时就报错了:fatal error LNK1120: 1 个无法解析的外部命令说明在 main.cpp 里面的 test 并没有被找到。解决这个问题就需要 extern "C" 出场了,如下所示:

//main.cpp
extern "C"{
#include "a.h"
} int main()
{
test(,1.2);
getchar();
return ;
}

  通过以上这种方式当然就能成功运行了,extern "C" 的作用就是告诉 C++ 编译器你不要把我的 "a.h" 里的内容当C++语法来编译,给我原封不动的当 C 语言的语法来编译。当然也可以换用下面的这种写法:

//main.cpp
#include <iostream>
using namespace std; extern "C" void test(int x, double y);
int main()
{
test(,1.2);
getchar();
return ;
}

C 调用 C++函数:

  上面给大家展示了C++语言如何调用C函数,那么C语言又如何调用C++函数呢?

//b.h
#pragma noce
#include <iostream>
using namespace std; #ifdef __cplusplus
extern "C" {
#endif void test(); #ifdef __cplusplus
}
#endif
//b.cpp

#include "b.h"

void test()
{
cout << "hello world" << endl;
}
//main.c
#include <stdio.h> extern void test();
int main()
{
test();
getchar();
return ;
}

  以上就是今天的全部收获了,分享给大家。

浅谈 extern "C"的更多相关文章

  1. 转载 浅谈C/C++中的static和extern关键字

    浅谈C/C++中的static和extern关键字 2011-04-21 16:57 海子 博客园 字号:T | T   static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.ext ...

  2. 转:浅谈C/C++中的指针和数组(一)

    再次读的时候实践了一下代码,结果和原文不一致 error C2372: 'p' : redefinition; different types of indirection 不同类型的间接寻址 /// ...

  3. 浅谈C语言中的强符号、弱符号、强引用和弱引用

    摘自http://www.jb51.net/article/56924.htm 浅谈C语言中的强符号.弱符号.强引用和弱引用 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014- ...

  4. 浅谈 .NET 中的对象引用、非托管指针和托管指针 理解C#中的闭包

    浅谈 .NET 中的对象引用.非托管指针和托管指针   目录 前言 一.对象引用 二.值传递和引用传递 三.初识托管指针和非托管指针 四.非托管指针 1.非托管指针不能指向对象引用 2.类成员指针 五 ...

  5. 浅谈Windows API编程

    WinSDK是编程中的传统难点,个人写的WinAPI程序也不少了,其实之所以难就难在每个调用的API都包含着Windows这个操作系统的潜规则或者是windows内部的运行机制…… WinSDK是编程 ...

  6. 【原创】浅谈指针(十二)关于static(上)

    0.前言 这个系列基本上是一月一更到两月一更 今天写一篇关于static的,内含大量干货,做好准备 1.基础知识的回顾 1.1.内存的种类 一般来说,我们之前已经讲过的变量(或者说是内存)可以大体分为 ...

  7. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  8. 浅谈 LayoutInflater

    浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...

  9. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

随机推荐

  1. LeetCode 246. Strobogrammatic Number (可颠倒数字) $

    A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside ...

  2. 5.Swift教程翻译系列——Swift字符串和字符

    英文版PDF下载地址http://download.csdn.net/detail/tsingheng/7480427 字符串是一组字符的有序序列,比方"hello,china"或 ...

  3. 我不常用的 javascript

    获取当前时间:new Date    (最后的调用括号可加可不加) 获取当前时间戳: 方法1:Date.parse(new Date()) 方法2:(new Date()).valueOf() 方法3 ...

  4. java中不能使用小数点(.)来作为分隔符

    split()括号里是一个String的参数,所以一定要符合这种:split(".")形式,即点'.'要用双引号""括起来"."在java中 ...

  5. C - Gr-idian MST

    Time limit : 2sec / Memory limit : 256MB Score : 500 points Problem Statement On an xy plane, in an ...

  6. ubuntu系统jdk安装及环境变量配置

    一.安装jdk 1.下载linux版本jdk,我用的是最新版本1.8.0_102 2.打开终端,进入jdk的存放路径 3.解压.tar.gz文件 sudo tar zxvf jdk-8u102-lin ...

  7. java.io.IOException: The same input jar is specified twice

    简介: eclipse android proguard 打包时出现 java.io.IOException: The same input jar is specified twice 错误, 这里 ...

  8. bzoj2538: [Ctsc2000]公路巡逻

    超车这个东西这么恶心肯定是要暴力求的(自圆其说) 那么分成一个个时间段来搞,然后DP一下 化一下那个速度,耗费时间是在300s~600s之间的 那我们就可以设f[i][j]为走到第i个位置用了j的时间 ...

  9. 2.android

    ImageButton action_btn = (ImageButton) findViewById(R.id.action_btn);action_btn.setOnClickListener(n ...

  10. Gym - 101982B 2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) B. Coprime Integers Mobius+容斥 ab间gcd(x,y)=1的对数

    题面 题意:给你 abcd(1e7),求a<=x<=b,c<=y<=d的,gcd(x,y)=1的数量 题解:经典题目,求从1的到n中选x,从1到m中选y的,gcd(x,y)=k ...