C/C 语言中extern的用法

声明外部变量

    现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相透明的,也就是说,在编译时,全局变量的可见域限制在文件内部。下面举一个简单的例子。创建一个工程,里面含有A.cpp和B.cpp两个简单的C 源文件:

//A.cpp
int i;
void main()
{
}
//B.cpp
int i;

    这两个文件极为简单,在A.cpp中定义了一个全局变量i,在B中也定义了一个全局变量i。对A和B分别编译,都可以正常通过编译,但是进行链接的时候,却出现了错误,错误提示如下:

linking...
B.obj:errorLNK2005: "int i" (?i@@ 3HA ) already defined in A.obj
Debug/A.exe:fatal error LNK1169: one or more multiply defined symbols found
Error executing link.exe.
A.exe - 2 error(s), 0 warning(s)

    这就是说,在编译阶段,各个文件中定义的全局变量相互是透明的,编译A时觉察不到B中也定义了i,同样,编译B时觉察不到A中也定义了i。但是在链接阶段,要将各个文件的内容“合为一体”,因此,如果某些文件中定义的全局变量名相同的话,在链接阶段就会报重复定义(one or more multiply defined symbols)的错误。

    因此,各个文件中定义的全局变量名不可相同。

    在链接阶段,编译产生的obj文件合并了A、B两文件的内容,这也是出现int i重复定义错误的原因。

举个例子

    一个文件中定义的全局变量,可以在整个程序的任何地方被使用,举例说,如果A文件中定义了某全局变量,那么B文件中也可以使用该变量。修改我们的程序,加以验证:

//A.cpp
void main()
{i = 100;  //试图使用B中定义的全局变量
}
//B.cpp
int i;

    出现如下意料之中的编译错误,未定义int i错误(undeclared identifier Error),因为在链接之前A、B文件中的变量是彼此不可见的。

Compiling...
A.cpp 
C:/Documents and Settings/wangjian/桌面/try extern/A.cpp(5) : error C2065: 
'i' : undeclared identifier
Error executing cl.exe.
A.obj - 1 error(s), 0 warning(s)

    编译器没有能够意识到,某个变量符号虽然不是本文件定义的,但是它可能是在其它的文件中定义的,为了避免错误的发生extern派上用场了。为上面的错误程序加上extern关键字后,顺利通过编译,链接,代码如下:

//A.cpp
extern int i;
void main()
{  i = 100; //试图使用B中定义的全局变量
}
//B.cpp
int i;

在C 文件中调用C方式编译的函数

    相对于C,C 中新增了诸如重载等新特性,它们的编译有一些重要区别。将下面的小程序分别按C和C 方式编译,来探讨两种编译方式的区别。

int i;
int func(int t)
{return 0;
}
void main()
{
}

    以C方式编译的结果如下:

COMM   _i  :  DWORD
PUBLIC   _func
PUBLIC   _main

    以C 方式编译的结果如下:

PUBLIC  ?i@@ 3HA     ; i
PUBLIC  ?func@@YAHH@Z  ; func
PUBLIC  _main

    可见,C方式编译下,变量名和函数名之前被统一加上了一个下划线,而C 编译后的结果却复杂的多,i变成了?i@@ 3HA ,func变成了?func@@YAHH@Z。C 中的这种看似复杂的命名规则是为C 中的函数重载,参数检查等特性服务的。

不同编译方式下的函数调用

    如果在工程中,不仅有CPP文件,还有以C方式编译的C文件,函数调用就会有一些微妙之处。有如下CPP文件A.CPP和C文件B.C两个文件。

//A.CPP
void func();
void main()
{func();
}
//B.C
void func()
{
}

    对A.CPP和B.C分别编译,都没有问题,但是链接时出现错误,原因就是C和CPP不同的编译方式产生的冲突。比如在上文中提到,C方式编译下,变量名和函数名之前被统一加上了一个下划线,而C 编译后的结果却复杂的多,i变成了?i@@ 3HA。

linking...
A.obj : error LNK2001: unresolved external symbol "void __cdecl func(void)" (?func@@YAXXZ)
Debug/A.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
A.exe - 2 error(s), 0 warning(s)

    此时,可以通过extern关键字,来帮助编译器解决上面提到的问题。对于本例,只需将A.CPP改成如下代码即可:

//A.CPP
extern "C"
{void func(); //引入C语言方式编译的函数或变量
}
void main()
{func();
}

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设置公共请求参数_封装一个useFetch实现页面销毁取消请求

前端业务经常会出现这样一类问题,当用户网速过慢或是其他特殊情况下,该页面的请求还未完成,用户就已经点击其他页面跳出去了。理想状态下请求也是应该终止掉的,所以我们应该想办法将请求和页面卸载关联在一起。1 使用AbortControl…

C语言中return的各种用法

按初学的理解,return的任务就是返回对应的参数,在外层函数中对这个参数做进一步处理。实际上return的用法不只这些。为调用的函数返回参数值此类应用最为普遍,通常是在一个具有返回值的函数中,返回一个参数值,这个返回…

代码内查找函数引用_叮~~二级操作题 excel常考函数大梳理

1.AND函数格式:AND(logical1,logical2…)功能:and函数是一个逻辑函数,表示同时满足多个条件。通常配合if函数做条件判断,得值为true或者是false。2.OR函数格式:OR(logical1,logical2…)功能:or函数是一个逻…

总结C语言中的数组知识点

数组:只能存放一种数据类型,比如int类型的数组、float类型的数组,里面存放的数据称为“元素”。数组的定义:首先声明数组的类型,然后声明数组元素的个数,也就是定义需要多少存储空间。数组格式与初始化格式…

主要矛盾和次要矛盾_次要GC,主要GC与完整GC

主要矛盾和次要矛盾在使用Plumbr中的GC暂停检测功能时,我被迫通过大量有关该主题的文章,书籍和演示工作。 在整个旅程中,我多次对次要,主要和完全GC事件的使用(误用)感到困惑。 这导致了这篇博客文章&#…

action mutation 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

module与moduleCollection你一定要会啊!Vuex源码学习(五)加工后的module在组件中使用vuex的dispatch和commit的时候,我们只要把action、mutation注册好,通过dispatch、commit调用一下方法名就可以做到。使用方式vue组件内//in vue componentt…

​嵌入式开发为什么选择C语言?

从语言特点来说C语言有出色的可移植性,能在多种不同体系结构的软/硬平台上运行。简洁紧凑,使用灵活的语法机制,并能直接访问硬件能够直接访问硬件的语言有:汇编和C语言汇编属于低级语言,难以完成一些复杂的功能&#x…

序列化与反序列化的单例模式_序列化代理模式

序列化与反序列化的单例模式在上一篇文章中 ,我谈到了一般的序列化。 这是更加集中的内容,并提供了一个细节: 序列化代理模式 。 这是处理序列化中许多问题的一种好方法,通常是最好的方法。 如果开发人员只想了解这一主题&#xf…

图解C语言的希尔排序

希尔排序是插入排序的一种,又称“缩小增量排序”,希尔排序是直接插入排序算法的一种更高效的改进版本。希尔排序的基本思想设等待排序等元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为n/inc…

给oim_对OIM Web(UI)层进行压力测试

给oimOracle IDM中的默认配置保留20个专用于服务前端(UI)请求的线程 。 这基本上意味着应用程序服务器具有20个线程池,可用于为通过Web控制台(/ identity或/ sysadmin)访问OIM的用户提供服务。 对于Weblogic &#xf…

C语言打印输出红色字体

除了Linux,在VS下也可以实现变色这一效果,先看下面的一段代码:#include int main(int argc,char **argv){ printf("\033[44;37;5m hello world\033[0m\n");return 0;}编译后运行上述代码,结果如下:可见&…

mysql g月份分组_PowerBI快捷键——视觉对象分组功能

PowerBI的2020年4月份更新虽然发布在5月份,但的确是提供了很多强大的功能。在以往,要选中多个视觉对象,往往需要按住CTRL键挨个单击选中,然后在进行下一步的分组或其他操作。但是在4月份更新中,PowerBI允许我们通过在画…

编译原理抽象语法树_平衡抽象原理

编译原理抽象语法树使代码复杂易读和理解的一件事是&#xff0c;方法内部的指令处于不同的抽象级别。 假设我们的应用程序仅允许登录用户查看其朋友的旅行。 如果用户不是朋友&#xff0c;则不会显示任何行程。 一个例子&#xff1a; public List<Trip> tripsByFriend…

谈谈单片机编程思想——状态机

玩单片机还可以&#xff0c;各个外设也都会驱动&#xff0c;但是如果让你完整的写一套代码时&#xff0c;却无逻辑与框架可言。这说明编程还处于比较低的水平&#xff0c;你需要学会一种好的编程框架或者一种编程思想&#xff01;比如模块化编程、状态机编程、分层思想等。本文…

C语言结构体使用与指针的理解

以前总有一种疑惑。为什么结构体的指针有的需要用分配空间&#xff1f;有的不需要分配空间呢&#xff1f;现在总结一下思路&#xff1a;一&#xff1a;关于结构体的定义问题&#xff1a;使用结构体一般会使用变量或者定义指针typedef struct{ int a; int b; }data;使用这个结构…

elementui 进度条怎么做_小E,Excel中这样的进度条是怎么做出来的?

我的目标&#xff1a;让中国的大学生走出校门的那一刻就已经具备这些office技能&#xff0c;让职场人士能高效使用office为其服务。支持我&#xff0c;也为自己加油&#xff01;前面我们分享过如何做进度条&#xff1a;《Excel进度条启示&#xff1a;专注与持续积累定会让人生出…

C语言结构体描述BMP的文件格式

BMP文件的结构其实非常简单&#xff0c;就是两个结构体&#xff0b;一个可选的调色板&#xff0b;位图数据。第一个结构体是BITMAPFILEHEADER&#xff0c;第二个结构体是BITMAPINFOHEADER。然后就是可选的调色板&#xff08;RGBQUAD数组&#xff09;。最后是位图数据。第一个结…

php mysql 常用语句_PHP mysql基本语句指令

1 /* 选择数据库 2 use test; 3 */ 4 5 /* 显示所有的数据库 6 show databases; 7 */ 8 9 /* 删除表/数据库 10 drop database test1; 11 delete from user1 where id4; 12 */ 13 14 /* 创建表 15 CREATE TABLE user1( 16 id int primary key auto_increment1 /*选择数据库2 us…

C语言Main函数到底有几种,你真的懂吗?

乍一看标题&#xff0c;感觉小编小题大做&#xff0c;但凡学过C语言的聚聚&#xff0c;都知道C程序入口就是main函数&#xff0c;且一套程序里面有且仅有一个。但是很多时候我们看到的main函数却并不是千篇一律&#xff0c;格式竟然会有差别&#xff0c;这究竟是为啥&#xff1…

python大型项目经验_图像分类:13个Kaggle项目的经验总结

来源&#xff1a;数据派THU任何领域的成功都可以归结为一套小规则和基本原则&#xff0c;当它们结合在一起时会产生伟大的结果。机器学习和图像分类也不例外&#xff0c;工程师们可以通过参加像Kaggle这样的竞赛来展示最佳实践。在这篇文章中&#xff0c;我将给你很多资源来学习…