回 帖 发 新 帖 刷新版面

主题:关于extern声明全局变量的用法

这篇文章主要讲解一下extern声明全局变量的一些用法,虽然知识点比较浅显,但是却容易犯错,仅与那些初学C++的朋友分享,希望没有让大牛们见笑。
extern最基本的用法是声明全局变量的。这里需要注意两点,一是“声明”,二是“全局变量”;我们先来分析这两个概念。
声明:声明和定义是有区别的。声明不等于定义,声明只是指出了变量的名字,并没有为其分配存储空间;定义指出变量名字同时为变量分配存储空间,定义包含了声明。例如:
extern  int  i;  //声明变量i,但没分配存储空间,还不能使用。
int  i;         //定义了变量i,并分配了空间,可以使用。
注意:在程序中一个变量可以声明多次,但只能定义一次。
如果声明时有初始化式,也会被当做定义,例如:
extern  int  i = 5; //定义了变量5
后面的程序中若再出现extern  int  i = 5;或者int  i;的语句,就会出错,因为变量只能定义一次。
全局变量:通俗讲,在函数内部定义的变量称为局部变量,它的作用域是从定义处知道函数结束;在函数外部定义的称为全局变量,它的作用域是从定义处直到文件结束。
注意:不管是全局变量还是局部变量,作用域都是从定义处开始的。例如:
int main()
{
cout<<i<<endl;  //错误,会提示变量i未定义
    int i=5;        //变量i的作用域从这里开始
    return 0;
}
理解了这两个概念,我们回过头看extern的作用。extern的作用是扩大全局变量的作用域,本来全局变量的作用域是从定义处开始直到文件结束,使用extern提前声明之后就变成从声明处开始,直到文件结束。那么,对于上面这个程序,作如下修改时不是就对了呢?
int main()
{
    extern int i;
    cout<<i<<endl;
    int i=5;
    return 0;
}
其实是错误的,因为前面说了,extern是用来声明全局变量的,而i是局部变量,如果将变量i在main函数外部定义就对了,如下:
int main()
{
    extern int i;    //声明之后,变量i的作用域从该处开始直到文件结束。
    cout<<i<<endl;   
    return 0;
}
int i=5;
使用:在实际编程中,有时程序需要包含多个源文件,若这些文件有共同使用的变量,那么这个变量就遵循“一次定义,多次声明”的形式。即在一个文件中定义,其他文件使用时先进行声明。例如在文件file1中定义了一个变量:
file1:
int  i =5;
若想在文件file2也使用这个变量,就可以如下:
file2
extern  int  i;  //此时,编译器就知道i是一个已在其他地方定义的变量,会自动在本文件
              //或其他文件中搜寻
i=6;   //声明之后,就可在file2中对变量操作
注意:这种使用对于const变量是个例外。Const类型变量默认为当前文件的局部变量,即便在其他文件中声明了也不能使用。要想在其他文件中使用,定义const类型变量时必须在前面显式指出是extern。例如:
file1:
extern  const  int  i=5;
此时就能在其他文件中声明并使用了。具体这反面的原因和头文件的使用有关,这里就不详述了。

回复列表 (共3个回复)

沙发

语法(表达式的优先级,左右值,结合率),语句(三种结构),函数(参数的传递只是 值的拷备)
作用域--文件作用域,函数作用域,代码块作用域,原型作用域(参数名),而标识符的作用域与它的链接属性有关,但这两属性并不相同,链接属性--external,internal,none
在缺省情况下为external,none
关键字 extern和static用于在声明中修改标识符的链接属性,在缺省external的情况下前面加static可以使它的链接属性变成internal
存储类型:普通内存,运行时的堆栈,硬件寄存器
当 static用于代码块内部的变量声明时,是用来修改变量的存储类型的
注:在C51中有如下规定
[存储种类] 数据类型 [存储器类型] 变量名
  extern    bit         bdata     Test

PS:LZ能详解一下作用域与生存周期就完整了,最近看C的一些小结

板凳


    关于C51中地址的小结
    MSC-51 系列包括多种寄存器,其中一些具有特殊功能,如定时器,端口的控制寄存

器等,为了能够直接访问这些寄存器,C51编译器提供了一种定义的自主形式,这是必要

的,因为这些定义与标准C语言是不兼容的。
为了支持这些特殊功能寄存器(SFR)的声明,引入了关键词“sfr”,语法如下:
sfr-dcl:sfr sfr_name=int_constant
“=”号后的地址必须是常数,不允许带有运算符的表达式,这个常数表达式必须在特殊功

能寄存器的地址范围内,位于0X80到0XFF之间     例:sfr p0=0x80;
   既然它是个地址,我们可不可以通过 (char *)0x80来访问呢,我们可以测试下
   *(uchar *)0x80=01;//这个不是SFR的地址,这个是RAM中地址,它地址由存储器选择
而不同,如下
存储器类型                   描                    述

   data 直接寻址内部数据存贮器,访问变量速度最快(128bytes)

   bdata 可位寻址内部数据存贮器,允许位与字节混合访问(16 bytes)

   iIdata 间接寻址内部数据存贮器,可访问全部地址空间(256bytes)MOV @Ri访问

   pPdata 分页(256bytes)外部数据存贮器,由操作码MOVX @Ri访问

   xdata 外部数据存贮器(64K),由MOVX @DPTR访问

   code 代码数据存贮器(64K),由MOVC @A+DPTR访问

抽象指针类型用来在每个存贮区访问任意绝对地址,或来产生绝对CALLs。在这个过程

中,常数类型或字符型、整型都用抽象类型作了原则性修改(类型整理)以允许进行绝

对访问或调用。
指针定义格式:
指针变量自身所在存储区  类型标识符  指针变量指向的存储区 *指针变量名
data uchar xdata *p
例: 
char xdata *px;
char idata *pi;
char code *pc;
char c;
int i;

pc = (void*)main;

i = ((int(code*)(void))0xFF00();   /*LCALL 0FF00H */

c = *((char code*)0x8000);     /*char [code[0x8000]]*/

i = *((int code*)0x1200);     /*int from code[0x1200]*/

px = *((char xdata *xdata*)0x4000);    /*x ptr from xdata[0x4000]*/

px = ((char xdata *xdata*)0x4000)[0]; /*同上*/
用“#include <absacc.h> ”即可使用其中定义的宏来访问绝对地址
#define CBYTE ((unsigned char volatile code  *) 0)
#define DBYTE ((unsigned char volatile data  *) 0)
#define PBYTE ((unsigned char volatile pdata *) 0)
#define XBYTE ((unsigned char volatile xdata *) 0)
例:
#define COM8255 XBYTE[0X060FF]

PS:因内容与本版内容不是很符,借LZ地方一用,没意见吧。。。哈哈

3 楼

寻找中国的最优秀的网商领袖精英  
当今世界正经历着全球经济一体化的大潮,中国本土企业也因此面临着前所未有的机遇与挑战。
在这场洗礼中,哪些互联网平台有能力成为世界级的电子商务平台?网商精英要怎样做,才能最终成长为世界级网商精英领袖?
淘宝商盟平台震撼登场,携手淘宝30万商家联盟购物商城。
平台刚刚启动,互联网的网商精英请咨询qq: 908889846 
占领市场第一先机,合力打造网商系统!
淘宝商盟官网   www.taobaosm.com
 http://blog.sina.com.cn/tbsm8
淘宝商盟奖励制度

我来回复

您尚未登录,请登录后再回复。点此登录或注册