栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

extern与static用法介绍

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

extern与static用法介绍

今天在整理入职考试时候的错题,发现还有很多不会的地方,所以打算写一些博客记录下来。

extern

extern是C语言里面的关键字,用于修饰变量和函数,被extern修饰说明变量和函数不在本文件内或在使用的时候还没有被定义。

这里我们举一个例子来解释,这个例子里面有两个文件extern.c和extern_2.c

extern.c的内容如下:

#include 

extern int func();

int main()
{
    func(); 
    extern int num;
    printf("%d", num); 
    return 0;
}

extern_2.c的内容如下:

#include 

int func()
{
    extern int num;
    printf("%dn", num);
}

int num = 7;

extern.c中用到了func函数和num变量,但是具体的内容是在extern_2.c中定义的,在编译的时候将两个文件一起编译,就可以正常执行main函数。

extern_2.c中,在输出num的时候num还没有定义,因此添加了extern int num,num变量之后再定义。

这就是extern的几种典型的用法,引用其他文件的变量/函数和引用之后才出现的变量/函数。

extern真正的意思是通知编译器,此处只是该变量或函数的声明,不会分配内存,而真正的定义在别处。

同时,extern定义的变量或函数在另一个文件里必须是全局的,本文件局部变量不能被其他文件引用。


extern声明的变量在函数外时,才可以进行初始化。
同时一个变量只能初始化一次。

这里我们举一个例子

#include 

int main()
{
    extern int num = 6;
    printf("%dn", num);
}

int num = 7;

这样会直接出现编译错误

extern_2.c: In function ‘main’:
extern_2.c:7:16: error: ‘num’ has both ‘extern’ and initializer
    7 |     extern int num = 6;
      |                ^~~

解析:num变量是在最后一行被定义的,之后extern不能再对其进行初始化。

备注:默认所有的函数和全局变量都可以被extern修饰。


在这一部分我由于失误发现了两个小问题

Question1:

#include 

int num = 7;

int main()
{
    int num;
    printf("%dn", num);
}

输出

0

全局变量与局部变量同名的情况下,优先使用了局部变量。

同时局部变量没有初始化的情况下,gcc会将其初始化,并初始化为0。我本来以为会直接报错,其实编译器还是蛮智能的。据我查找的资料,Windows上也是这么处理的。

具体初始化为多少这件事在Windows与Linux上是不同的,Windows会将其初始化为-858993460。

Question2:

extern.c

#include 

extern int func();

int main()
{
    func(); 
    extern int num;
    printf("%d", num); 
    return 0;
}

extern_2.c

#include 

int num = 7;

int func()
{
    int num;
    printf("%dn", num);
}

输出

gcc -o extern extern.c extern_2.c

./extern

22087    #每次输出的值都不一样
7

这是另外一种情况了,同样是全局变量和局部变量同名,局部变量没有初始化,但是这次编译器没有单独对局部变量进行初始化,是直接输出了内存里存储的内容,原因暂时不明,这里先记录一下。等我日后研究明白了补上。


static

被static修饰的全局变量和全局函数只能在本文件内使用,不能被其他文件使用。它们被称为静态变量和静态函数。

还是以上面那段代码为例

extern.c的内容如下:

#include 

extern int func();

int main()
{
    func(); 
    extern int num;
    printf("%d", num); 
    return 0;
}

extern_2.c的内容如下:

#include 

static int num = 7;
static int func()
{
    printf("%dn", num);
}

输出

/usr/bin/ld: /tmp/ccc2TEVS.o: in function `main':
extern.c:(.text+0xe): undefined reference to `func'
/usr/bin/ld: extern.c:(.text+0x14): undefined reference to `num'
collect2: error: ld returned 1 exit status

我只是在第一份代码的基础上在num和func前面用static修饰了,因此它们就不能被其他文件访问,会有报错找不到num和func的报错。

为了更进一步解释extern与static区别还需要引入存储方式:

  1. 静态存储:固定存储空间的变量,比如全局变量和static变量
  2. 动态存储:动态分配存储空间的变量,使用完成之后存储空间会回收,各种局部变量

存储相关的关键字

auto:在函数内使用,函数调用完结束则释放内存(局部变量默认为auto)
static:函数调用结束后不释放内存,保留值。
register:局部变量使用频繁,可以用register,意思是把变量放在CPU中的寄存器中,运算时可以更快的取到这个值,而不用去内存中取值
extern:可以跨文件使用。


2022.05.11日补充 static修饰局部变量的情况

这里再补充一下static的实际用法,明明刚刚研究过static的用法,还是有没学到的部分,学艺不精啊。

#include 
void fun(int *s)
{
    printf("Start n");
    static int j = 0;
    do
    {
        printf("Loop j = %dn", j);
        s[j] += s[j + 1];
    } while (++j < 2);
}
int main()
{
    int i, a[10] = {1, 2, 3, 4, 5};
    for (i = 1; i < 3; i++)
        fun(a);
    for (i = 1; i < 5; i++)
        printf("a[%d]为%d t", i, a[i]);
    printf("n");
    return 0;
}

输出

Start 
Loop j = 0
Loop j = 1
Start 
Loop j = 2
a[1]为5 	a[2]为7 	a[3]为4 	a[4]为5 	

这道题主要考察了static,do while还有变量的自增。

难点解析:

这里面用到static用于修饰局部变量int j,被修饰之后变量被保存在全局数据区,上一次的值会保持到下一次调用。

原因是j被static修饰之后会变成静态变量,静态变量在其先前的作用域中保留先前的值,不会在新的作用域中被再次初始化。因此第二次循环中j不是从0开始的而是从上一次的值开始。

同时j++是先自增再赋值,因此while只能循环两次。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/876841.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号