什么是全局变量,局部变量,静态全局变量,静态局部变量

article/2025/9/21 20:07:50

来源:公众号【编程珠玑】

作者:守望先生

 

前言

这些是编程语言中的基本概念,如果你还不是非常明确地清楚标题的问题,并且不知道作用域,链接属性,存储期等概念的具体含义,那么本文你不该错过。为了更加清晰的理解我们的问题,需要先了解三个概念:作用域,链接属性,存储期。

作用域

C语言中,作用域用来描述标识符能够被哪些区域访问。

而常见作用域有以下几种:

为了便于说明,我们来看一个例子,就很容易理解了:

/****************************作者:守望先生来源:公众号编程珠玑个人博客:https://www.yanbinghu.com***************************************/#include <stdio.h>int num1 = 222;         //定位在函数外,具有文件作用域static int num2 = 111;  //定义在函数外,具有文件作用域int swap(int *a,int *b); //这里的a,b是函数原型作用域int swap(int *a,int *b){    if(NULL== a || NULL == b)        goto error;        else    {        int temp = *a;  //定义在函数内,块作用域        *a = *b;        *b = temp;        return 0;    }    //printf("temp is %d\n",temp);   //因为temp具有块作用域,因此在这里不能直接使用    error://goto语句的标签,函数作用域,因此在前面就可以引用        {            printf("input para is NULL\n");            return -1;        }}int main(void){    printf("num1=%d,num2=%d\n",num1,num2);    swap(&num1,&num2);  //num1 num2具有文件作用域,可以在main函数中直接使用    printf("num1=%d,num2=%d",num1,num2);    return 0;}
#include <stdio.h>
int num1 = 222;         //定位在函数外,具有文件作用域
static int num2 = 111;  //定义在函数外,具有文件作用域
int swap(int *a,int *b)//这里的a,b是函数原型作用域
int swap(int *a,int *b)
{
    if(NULL== a || NULL == b)
        goto error;    
    else
    {
        int temp = *a;  //定义在函数内,块作用域
        *a = *b;
        *b = temp;
        return 0;
    }
    //printf("temp is %d\n",temp);   //因为temp具有块作用域,因此在这里不能直接使用
    error://goto语句的标签,函数作用域,因此在前面就可以引用
        {
            printf("input para is NULL\n");
            return -1;
        }
}
int main(void)
{
    printf("num1=%d,num2=%d\n",num1,num2);
    swap(&num1,&num2);  //num1 num2具有文件作用域,可以在main函数中直接使用
    printf("num1=%d,num2=%d",num1,num2);
    return 0;
}

可以看到,error标签具有函数作用域,整个函数内都可见,而temp具有块作用域,因此在大括号外部,不能直接使用它。而num1和num2具有文件作用域,因此main函数可以直接使用它。

链接属性

在《hello程序是如何变成可执行文件的》我们说到了编译的过程,最后一个步骤就是链接。链接属性决定了在不同作用域的同名标识符能否绑定到同一个对象或者函数。或者说,不同作用域的标识符在编译后是否是同一个实体。

c变量有三种链接属性:

再稍作解释,没有static修饰,且具有文件作用域的变量,他们在链接时,多个同名标识符的变量最终都绑定到同一个实体。而static修饰的具有文件作用域的变量就不一样了,不同文件内,即便标识符名字相同,它们也绑定到了不同的实体。

因此,如果我们希望某个变量或函数只在某一个文件使用,那么使用static修饰是一个很好的做法。

同样的,来看一个例子。

/****************************作者:守望先生来源:公众号编程珠玑个人博客:https://www.yanbinghu.com***************************************/#include <stdio.h>int a = 5;   //文件作用域,外部链接属性,其他文件可通过extern int a的方式使用该文件的astatic b = 6;  //文件作用域,内部链接属性,即便其他文件也有同名标识符,它们也是不同的int main(void){    int sum = 0 ; //无链接属性    sum = a + b;    printf("sum is %d\n",sum);    return 0;}
#include <stdio.h>
int a = 5;   //文件作用域,外部链接属性,其他文件可通过extern int a的方式使用该文件的a
static b = 6;  //文件作用域,内部链接属性,即便其他文件也有同名标识符,它们也是不同的
int main(void)
{
    int sum = 0 ; //无链接属性
    sum = a + b;
    printf("sum is %d\n",sum);
    return 0;
}

从代码中可以看到,a和b都具有文件作用域,a具有外部链接属性,而b具有内部链接属性,sum具有块作用域,因此无链接属性。

存储期

实际上作用域和链接属性都描述了标识符的可见性,而存储期则描述了这些标识符对应的对象的生存期。存储期,也分下面几种:

关于初始化,可参考《C语言入坑指南-被遗忘的初始化》。
同样地,我们通过下面的代码来更好地理解存储期:

/****************************作者:守望先生来源:公众号编程珠玑个人博客:https://www.yanbinghu.com***************************************/#include <stdio.h>int num1 = 222;         //静态存储期static int num2 = 111;  //静态存储期int add(int a,int b){    static int tempSum = 0;  //静态存储期    tempSum = tempSum + a + b;    return tempSum;}int main(void){    printf("num1=%d,num2=%d\n",num1,num2);    int sum = 0;  //自动存储期    sum = add(num1,num2);    printf("first time sum=%d\n",sum);//sum = 333    sum = add(num1,num2);    printf("second time sum=%d\n",sum); //sum = 666    return 0;}
#include <stdio.h>
int num1 = 222;         //静态存储期
static int num2 = 111;  //静态存储期
int add(int a,int b)
{
    static int tempSum = 0;  //静态存储期
    tempSum = tempSum + a + b;
    return tempSum;
}
int main(void)
{
    printf("num1=%d,num2=%d\n",num1,num2);
    int sum = 0;  //自动存储期
    sum = add(num1,num2);
    printf("first time sum=%d\n",sum);//sum = 333
    sum = add(num1,num2);
    printf("second time sum=%d\n",sum); //sum = 666
    return 0;
}

另外,如果我们通过nm命令查看编译出来的程序文件的符号表,我们可以找到num1,num2,tempSum,而没有sum,前者所用的内存数量在编译时就确定了。关于nm命令的使用可以参考《linux常用命令-开发调试篇》。

$ gcc -g -o lifetime lifetime.c $ nm lifetime|grep num10000000000601038 D num1$ nm lifetime|grep num2000000000060103c d num2$ nm lifetime|grep tempSum0000000000601044 b tempSum.2289$ nm lifetime|grep sum$|grep num1
0000000000601038 D num1
$ nm lifetime|
grep num2
000000000060103c d num2
$ nm lifetime|grep tempSum
0000000000601044 b tempSum.2289
$ nm lifetime|
grep sum
$

什么全局变量,局部变量,静态局部变量,静态全局变量

到这里,我们就可以很容易区分上面的变量类型了。实际上这里只是换了一种说法:
全局:具有文件作用域的变量
静态:具有静态存储期或内部链接属性
局部:具有函数或块作用域的变量

因而结合起来,也就很好理解了。

当然,这仅仅是为了区分它们,这并不是它们的严格定义。更好的方法,是通过代码来理解:

#include <stdio.h>int num1 = 222;         //全局变量static int num2 = 111;  //静态全局变量int add(int a,int b){    static int tempSum = 0;  //静态局部变量    tempSum = tempSum + a + b;    return tempSum;}int main(void){    printf("num1=%d,num2=%d\n",num1,num2);    int sum = 0;  //局部变量    sum = add(num1,num2);    printf("first time sum=%d\n",sum);//sum = 333    return 0;}
int num1 = 222;         //全局变量
static int num2 = 111;  //静态全局变量
int add(int a,int b)
{
    static int tempSum = 0;  //静态局部变量
    tempSum = tempSum + a + b;
    return tempSum;
}
int main(void)
{
    printf("num1=%d,num2=%d\n",num1,num2);
    int sum = 0;  //局部变量
    sum = add(num1,num2);
    printf("first time sum=%d\n",sum);//sum = 333
    return 0;
}

总结

本文总结如下:

参考

https://en.wikipedia.org/wiki/Global_variables

https://en.wikipedia.org/wiki/Local_variable

《C11标准文档》


关注公众号【编程珠玑】,获取更多Linux/C/C++/Python/Go/算法/工具等原创技术文章。后台免费获取经典电子书和视频资源

640?wx_fmt=jpeg


http://chatgpt.dhexx.cn/article/LWkxvTyY.shtml

相关文章

静态局部变量初始化

mask一下一直以来的一个误区 #include <stdio.h>void key(void) {static unsigned char key_up 1;printf("key_up %d \n", key_up);key_up 0;printf("key_up %d \n", key_up); }int main(void) {key();key();return 0; }原以为会每次调子函数时&…

C语言全局变量,局部变量,静态局部变量的区分

1.如果没有给全局变量和静态局部变量进行初始化赋值&#xff0c;全局变量与静态局部变量一样&#xff0c;默认值为数字0&#xff08;ASCII码为48&#xff09;&#xff1b; 2.非静态的局部变量没有初始化时&#xff0c;该变量的值是一个随机数&#xff0c;必须要赋值后才可以安…

C++中的静态局部变量

1 静态局部变量在静态存储区内分配存储单元。在程序运行期间都不释放。 2 对静态局部变量是在编译时赋初值的&#xff0c;即只赋值一次&#xff0c;在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上一次函数调用结束时的值。 3 静态局部变量&#x…

利用静态局部变量求阶乘

可以利用静态局部变量在在内存中不自动释放的特性&#xff0c;去计算阶乘&#xff0c;详细代码如下: #include <iostream> using namespace std;long CalcResult(int num) {static int result 1;result num*result;return result; }int main() {//采用静态局部变量计算…

C语言:静态局部变量(static局部变量)

题目概述&#xff1a; 考察静态局部变量的值。 编程&#xff1a; #include<stdio.h> int main() { int f(int);//函数声明 int a2,i;//自动局部变量 for(i0;i<3;i) printf("%d\n",f(a)); return 0; } int f(int a) { auto int b0;//自动局部变量 static int…

C中静态局部变量与局部变量的区别

#include<stdio.h> #include<stdlib.h> void fun() { int a 12;//局部变量 static int b 22;//静态局部变量 a; b; printf("a:%d,b:%d\n",a,b); } int main(void) { fun(); fun(); fun(); system("pause&quo…

静态局部变量和静态全程变量static。

1. 什么是static? static 是 C/C 中很常用的修饰符&#xff0c;它被用来控制变量的存储方式和可见性。 1.1 static 的引入 我们知道在函数内部定义的变量&#xff0c;当程序执行到它的定义处时&#xff0c;编译器为它在栈上分配空间&#xff0c;函数在栈上分配的空间在此函…

C++基础之static关键字(1)--静态局部变量详解

本篇文章主要讲解C基础中static关键字的静态局部变量并进行实例演示。 一.静态局部变量定义 在讲静态局部变量时&#xff0c;我们首先看一下全局变量和局部变量。 1.全局变量 全局变量定义在所有函数之外&#xff0c;并且在其作用域内的所有函数都可以访问。 2,局部变量 局部…

局部变量和静态局部变量

一、局部变量 局部变量也叫auto自动变量(auto可写可不写)&#xff0c;一般情况下代码块{}内部定义的变量都是自动变量&#xff0c;它有如下特点&#xff1a; 1、作用域 a.在一个函数内定义&#xff0c;只在函数范围内(也就是在定义变量的{}之内)有效 b.在复合语句中定义&…

静态局部变量(static)用法

有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值&#xff0c;即其占用的存储单元不释放&#xff0c;在下一次该函数调用时&#xff0c;该变量保留上一次函数调用结束时的值。这时就应该指定该局部变量为静态局部变量(static local variable)。 例 静态局部变量的…

Qt 5.14.1 安装详解

Qt 5.14.1官网下载参考 一、打开安装包 qt-opensource-windows-x86-5.14.1.exe&#xff0c;next 二、需要登录&#xff08;点击这里注册&#xff1a;https://www.qt.io/&#xff09; 三、 选择同意&#xff0c;next 四、 选择安装目录&#xff08;需要大约3.2G的空间大小&…

VS + QT安装及配置开发环境

应用场景&#xff1a; 适用于Windows平台下&#xff0c;需要使用VSQT环境进行开发的项目&#xff1b;本文以VS2019QT5.15.2为例 QT的下载及安装 1. 下载QT 可以去官网下载,也可以去镜像网站下载,目前QT5.15以后已经不支持下载离线安装包了,只支持下载在线安装程序.QT官方下载…

Linux Qt5的安装与环境配置

1. Qt官网下载http://www.qt.io/download-open-source/ 对应安装包 2. 我下的是qt-opensource-linux-x64-5.9.1.run&#xff0c;进入下载文件夹下&#xff0c;执行添加执行权限命令&#xff1a; sudo chmod x qt-opensource-linux-x64-5.9.1.run 然后执行安装命令&#xff1…

【Qt5.12】Qt5.12安装教程

目录 01. 软件下载 02. 软件安装 03. 软件测试 04. 附录 01. 软件下载 Qt5.12下载网址: http://download.qt.io/archive/qt/5.12/5.12.2/ 选择Windows平台, Linux和Mac平台类似 下载好之后的安装包: 02. 软件安装 Step1: 双击安装包, 稍等片刻, 然后点击next Step2: 如果没…

win10安装qt5.12保姆级教程(图文详解,简单快捷)

一、Qt简介 1、什么是Qt Qt是一个跨平台的C图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面所需的所有功能&#xff0c;它是完全面向对象的很容易扩展&#xff1b;并且允许真正的组件编程。 2、Qt的发展史 1991年&#xff0c;Qt最早由奇趣科开发。2014年…

ubuntu下安装Qt操作流程

一、下载Qt Linux 安装包 Qt的官方下载页面: https://download.qt.io/archive/qt/5.14/5.14.2/ 二、安装QT&#xff08;下载完成后执行qt安装&#xff0c;安装步骤傻瓜型操作&#xff0c;一路next下去&#xff0c;此过程不在做冗余讲解&#xff09;&#xff0c;安装完成后&…

VS2022+QT5.13.2环境配置及安装测试教程

下载和安装VS&#xff1a; &#xff08;1&#xff09;visual Studio2022下载链接&#xff1a;https://visualstudio.microsoft.com/zh-hans/?rrhttps://www.microsoft.com/zh-cn/ &#xff08;2&#xff09;下载完成后&#xff0c;打开VisualStudioSetup&#xff0c;点击继续…

Mac上Qt安装和配置教程

已剪辑自: https://www.cnblogs.com/GJ-ios/p/15674851.html 这是一篇非常适合Qt入门小白的的安装Qt教程&#xff0c;因为公司PC端开发桌面应用&#xff08;Mac和Windows&#xff09;&#xff0c;所以我选择安装Qt&#xff0c;这次我以这篇博客记录下来&#xff0c;分享给大家…

Qt5.14.2安装教程

之所以选择安装Qt5.14.2&#xff0c;是因为从5.15.0起&#xff0c;对于开源用户&#xff0c;Qt官方不再提供独立安装文件&#xff0c;源码安装听说很繁琐&#xff0c;并且还要激活码。 官网下载链接&#xff1a;https://download.qt.io/archive/qt/5.14/5.14.2/ 1、Windows用户…

Qt安装配置及连接MySQL

一、Linux系统 开发环境&#xff1a; 银河麒麟 Kylin V10Qt 5.6.1MySQL 5.7.27 1、安装配置Qt 在终端中通过命令安装Qt // 安装了该软件包&#xff0c;编译c/c所需要的软件包也都会被安装 sudo apt-get install build-essential // 安装Qt开发环境 sudo apt-get install c…