您的位置:首页 > 编程语言 > C语言/C++

C语言与C++中static,extern的用法及区别总结

2016-08-10 22:31 633 查看

在C语言中:

隐藏

  很多人经常会忘了这一条。其实这个作用很常用也很重要。

  当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。

  为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是a.c,另一个是main.c。

  

char a = 'A'; // global variable
void msg()
{
printf("Hello\n");
}


int main(void)
{
extern char a;
printf("%c ", a);
(void)msg();
return 0;
}


程序的运行结果是:

A Hello

  为什么在a.c中定义的全局变量a和函数msg能在main.c中使用?

  前面说过,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。 

  此例中,a是全局变量,msg是函数,并且都没有加static前缀,因此对于另外的源文件main.c是可见的。

  如果加了static,就会对其它源文件隐藏。

  

static char a = 'A'; // global variable
static void msg()
{
printf("Hello\n");
}
int main(void)
{
printf("%c ", a);
(void)msg();
return 0;
}


  上面的程序会输出什么呢?

  答案是:报错,找不到a与msg的定义。

  在a和msg的定义前加上static,main.c就看不到它们了。

  利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。

  static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏。

  在上面的例子中,含有一个新的关键字——extern

  下面来讲一下static和extern的区别:

extern

  extern告诉编译器这个变量或函数在其他文档里已被定义了。

  看下面的例子:

  

static int i; //只在a文档中用
int j;    //在工程里用
static void init()         //只在a文档中用
{
}
void callme()          //在工程中用
{
static int sum;
}

extern int j;     //调用a文档里的
extern void callme();  //调用a文档里的
int main()
{
...
}


  上面的全局i变量和init()函数只能用在a.c文档中,全局变量sum的作用域只在callme里。变量j和函数callme()的全局限扩充到整个工程文档。所以能够在下面的b.c中用extern关键字调用。extern告诉编译器这个变量或函数在其他文档里已被定义了。

extern C

  extern的另外用法是当C和C++混合编程时假如c++调用的是c源文档定义的函数或变量,那么要加extern来告诉编译器用c方式命名函数:

  

extern "C"  //在c++文档里调用c文档中的变量
{
int j;
void callme();
}
int main()
{
callme();
}


static法则:

  A、若全局变量仅在单个C文档中访问,则能够将这个变量修改为静态全局变量,以降低模块间的耦合度;

  B、若全局变量仅由单个函数访问,则能够将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;

  C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;

变量

1.变量定义的一般形式

存储类别数据类型变量表;

2.变量定义的作用

①规定了变量的取值范围。

②规定了变量进行的运行操作。

③规定了变量的作用域。

④规定了变量的存储方式。

⑤规定了变量占用的存储空间。

3.局部变量和全局变量

从作用域角度将变量分为局部变量和全局变量。它们采取的存储类别如下:

局部变量:

①自动变量,即动态局部变量(离开函数,值就消失)。

②静态局部变量(离开函数,值仍保留)。

③寄存器变量(离开函数,值就消失)。

④形式参数可以定义为自动变量或寄存器变量。

全局变量:

①静态外部变量(只限本程序文件使用)。

②外部变量(即非静态的外部变量,允许其它程序文件引用)。

动态存储和静态存储

  从变量存在时间可将变量存储分为动态存储和静态存储。

  静态存储是在整个程序运行时都存在,而动态存储则是在调用函数时临时分配存储单元。

动态存储:

①自动变量(函数内有效)。

②寄存器变量(函数内有效)。

③形式参数。

静态存储:

①静态局部变量(函数内有效)。

②静态外部变量(本程序文件内有效)。

③外部变量(整个程序可引用)。

静态存储区和动态存储区

  从变量值存放的位置可将变量存储区分为静态存储区和动态存储区:

内存中静态存储区:

①静态局部变量。

②静态外部变量。

③外部变量(可被同一程序其它文件引用)。

内存中动态存储区:自动变量和形式参数。

CPU中的寄存器:寄存器变量。

全局变量

  全局变量有外部、静态两种存储方式。

外部全局变量

  全局变量一般用外部存储方式存储,用保留字extern加以定义。此时,变量的作用域是构成整个程序的所有程序文件,也就是定义的外部变量可供其它程序文件使用。

  使用这样的全局变量一定要非常慎重,一旦产生错误,将波及整个程序。

静态全局变量

  如果希望全局变量仅限于本程序文件使用,而其它程序文件中不能引用,这时必须将其存储方式定义为静态存储方式,用保留字static加以定义。此时称为静态外部变量。

例如,在文件filel.c中,如果作这样的定义:

static int a:


  则变量a的作用域被缩小至本程序文件filel1.c,文件file2.c中不能引用。

  值得注意的是对全局变量加static,定义为静态存储方式,并不意味着是静态存储;而不加static,是动态存储。

  两种形式的全局变量(外部变量)都是静态存储方式,都是编译时分配存储空间,但作用域不同。使用静态外部变量,有利于隔离错误,有利于模块化程序设计。

全局变量的缺省存储方式是外部存储方式。

  前面章节中的程序没有见到变量的存储类别定义,实际上采用变量的缺省存储方式。对局部变量采用auto方式,对全局变量采用extern方式。这也是至今为止,我们在程序中没有见到auto、extern等的原因。

至此,我们对变量的存储类别及数据类型进行了全面讨论,在此作个小结。

局部静态变量

  在C/C++中, 局部变量按照存储形式可分为三种auto, static, register。其中register不常用到

  下面主要说说auto和static的区别。

  1. 存储空间分配和生存周期不同

auto类型局部变量就是普通的局部变量(不加修饰的局部变量默认为该类型)。该类型局部变量存储在栈上,在动态存储区,生命周期仅限于定义它的函数,函数结束,它就自动释放。static类型局部变量存储在静态存储区,在程序整个运行期间都不释放。两者之间的作用域相同,但生存期不同。

  2. static局部变量在所处模块在初次运行时进行初始化工作,且只操作一次。

  3. 对于局部静态变量,如果不赋初值,编译期会自动赋初值0或空字符,而auto类型的初值是不确定的

  对于C++中的class对象例外,class的对象实例如果不初始化,则会自动调用默认构造函数,不管是否是static类型

  特点: static局部变量的”记忆性”与生存期的”全局性”

外部静态变量/函数

  

  在C语言中 static有了第二种含义:

  用来表示不能被其它文件访问的全局变量和函数。

  但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。

  但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函 数)。

  注意此时, 对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区,生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.

  使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

静态数据成员/成员函数

前两种C和C++都有,这种仅在C++中有,下面作以下介绍:

  C+ +重用了这个关键字,并赋予它与前面不同的第三种含义:

  表示属于一个类而不是属于此类的任何特定对象的变量和函数.

  这是与普通成员函数的最大区别,也是其应用所在。

  比如在对某一个类的对象进行计数时, 计数生成多少个类的实例,就可以用到静态数据成员。

  在这里面, static既不是限定作用域的, 也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性. 这也是”属于一个类而不是属于此类的任何特定对象的变量和函数”的含义.。

  因为它是对整个类来说是唯一的,因此不可能属于某一个实例对象的.

  针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针。

  

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: