0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C/C++语言中extern的用法

单片机与嵌入式 来源:单片机与嵌入式 2023-11-29 14:34 次阅读

声明外部变量

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

//A.cpp
inti;
voidmain()
{
}
//B.cpp
int i;

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

Linking...
B.obj:errorLNK2005:"inti"(?i@@3HA)alreadydefinedinA.obj
Debug/A.exe:fatalerrorLNK1169:oneormoremultiplydefinedsymbolsfound
Errorexecutinglink.exe.
A.exe - 2 error(s), 0 warning(s)

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

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

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

举个例子

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

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

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

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

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

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

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

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

inti;
intfunc(intt)
{
  return0;
}
voidmain()
{
}

以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
voidfunc();
voidmain()
{
  func();
}

//B.C
void func()
{
}

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

Linking...
A.obj:errorLNK2001:unresolvedexternalsymbol"void__cdeclfunc(void)"(?func@@YAXXZ)
Debug/A.exe:fatalerrorLNK1120:1unresolvedexternals
Errorexecutinglink.exe.
A.exe - 2 error(s), 0 warning(s)

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

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

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 函数
    +关注

    关注

    3

    文章

    3903

    浏览量

    61310
  • C++
    C++
    +关注

    关注

    21

    文章

    2066

    浏览量

    72900
  • 编译器
    +关注

    关注

    1

    文章

    1577

    浏览量

    48625
  • extern
    +关注

    关注

    0

    文章

    7

    浏览量

    2907

原文标题:C/C++语言中extern的用法

文章出处:【微信号:单片机与嵌入式,微信公众号:单片机与嵌入式】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    SQLx在Rust语言中的基础用法和进阶用法

    SQLx是一个Rust语言的异步SQL执行库,它支持多种数据库,包括MySQL、PostgreSQL、SQLite等。本教程将以MySQL数据库为例,介绍SQLx在Rust语言中的基础用法和进阶
    的头像 发表于 09-19 14:32 3084次阅读

    单片机的C语言中位操作用法

    单片机的C语言中位操作用法
    发表于 08-17 15:04

    几个c语言中的问题(持续更新中)

    ,而后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误。有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在c++语言中只使用const常量而不使用宏常量,及const可以完全替代宏、
    发表于 05-06 22:25

    CC++中const的用法比较

    C语言中,通常使用#define来定义常数,其后在使用该常数的地方利用定义的宏名来进行常数替换,这样可以避免在程序中到处出现magic numbers的乱象,并且#define是宏定义,不需要为其
    发表于 11-11 10:00

    C语言C++的转变并不难!看完就懂了

    输入流。和C语言中的scanf用法类似,只是它用起来更为方便(大多数情况下),不需要区分不同的类型用不同的写法,所有类型只需要用cin >> (变量名)就可以了。第14行
    发表于 08-12 15:54

    C语言中的坑有哪些?

    总结几个C语言中的“坑”
    发表于 12-28 06:11

    C语言中atoi()函数的用法 相关资料分享

    C语言中atoi()函数的用法
    发表于 07-01 08:12

    extern有哪些用法

    extern可以用来在其他模块中公用变量和函数。其用法如:例如:在a.c文件中定义一个变量unsigned int intA; intA = 0x00;在b.c中要操作这个变量,就在
    发表于 07-15 06:28

    介绍一下关键字extern用法

    学单片机C语言一定要熟悉关键字的用法,本文介绍一下关键字extern用法。1、extern的定
    发表于 07-15 06:38

    C语言中的数据类型有哪几种?const有哪些用法

    C语言中的数据类型有哪几种?const有哪些用法?作用域与static用法是什么?extern是如何去使用的?
    发表于 07-22 06:51

    C语言C++运用

    ,一般将硬件初始化的工作交给汇编,比较复杂的操作交给C语言。③C语言具有很高的运行效率。2.嵌入式开发中的地位——开发工具3.高级语言中的低
    发表于 11-25 10:47

    请问C语言extern通常怎么使用?

    C语言extern通常怎么使用?哪位大神指点一下。
    发表于 10-08 10:55

    C51中断函数和汇编语言中断服务程序在用法上有什么不同?

    C51中断函数和汇编语言中断服务程序在用法上有何不同?
    发表于 10-17 08:31

    C语言中ASCII代码是什么意思?

    C语言中ASCII代码是什么意思常见的ASCII代码都需要记吗
    发表于 10-25 07:10

    C语言中的typedef的用法

    在以前的学习中对于C语言中typedef和define的认识是,#define是宏,作用是简单的替换,而typedef也是替换,只不过比define高级的是在替换的时候会进行语法检查。但是后来
    发表于 01-13 13:36 0次下载
    C<b class='flag-5'>语言中</b>的typedef的<b class='flag-5'>用法</b>