C/C++中extern和static
本篇博文主要是记录一下自己肤浅的理解,同时帮助跟我一样正在学习过程中的同伴。请大佬们指出文中不妥之处,万分感谢!
相信学习C/C++语言的小白对extern
并不陌生,根据自己的学习,和大家交流一下extern
的相关知识
1 extern概念
extern
是C/C++中的一个关键字,主要是针对变量和函数而言。
这里只讨论变量。
2 extern作用
extern
用于声明外部变量。提到这里,就不得不说一下声明和定义两个概念。
2.1 变量声明
声明:用于向程序表明变量的类型和名字。声明不分配内存空间。
2.2 变量定义
定义:给变量分配内存空间,还可以给变量赋初始值。
变量可以有多次声明,但是有且只能有一次定义
定义也是声明,但是extern
声明不是定义,也不分配内存空间,除非给extern
变量赋初值时才是定义
2.3 声明和定义举例
(1)未初始化
int i; //声明,也是定义,只不过没有初始化
extern int i; //声明,不是定义
(2)初始化
extern int i = 666; //有初始化,定义
3 为什么使用extern
比如说有a.c, b.c两个源文件和一个c.h头文件,当一个变量在a.c, b.c多个源文件中同时使用时,如果把变量在头文件c.h中定义,每个*.c文件都包含c.h这个头文件,这样编译器会提示变量多次定义的错误。
怎么来避免这个错误呢,就该extern
出场了。在一个源文件里定义这个变量,其他源文件使用这个变量时用extern
声明这个变量为外部变量。
4 怎么使用extern
4.1 基本数据类型定义变量
用基本数据类型定义变量时,只需在一个源文件里定义这个变量,其他源文件使用这个变量时用extern
声明这个变量为外部变量。例如:
在a.c中定义的变量b.c中要使用
/*a.c*/
#include<stdio.h>
int age;
int main()
{
age = 18;
printf("I am %d years old", age);
return 0;
}
/*b.c*/
#include<stdio.h>
extern int age; //声明为外部变量
int main()
{
age = 19;
printf("I am %d years old", age);
return 0;
}
4.2 自定义类型定义变量
若是自定义变量,比如结构体,结构体一般是在头文件中定义,那么两个源文件都要包含这个头文件。例如:
/*a.h*/
#pragma once
typedef struct _student
{
char name[20];
int age;
}student;
/*a.c*/
#include<stdio.h>
#include"a.h" //要包含头文件
student stu;
int main()
{
stu->age = 18;
printf("I am %d years old", stu->age);
return 0;
}
/*b.c*/
#include<stdio.h>
#include"a.h" //也要包含头文件
extern student stu;
int main()
{
stu->age = 19;
printf("I am %d years old", stu->age);
return 0;
}
5 static
static
用于定义静态变量。既可以修饰全局变量,又可以修饰局部变量;既可以用于面向过程程序设计,也可以用于面向对象程序设计。面向过程和面向对象使用static
关键字有不同。
static
修饰的静态变量,不管是全局静态变量还是局部静态变量,都是放在全局数据区。
5.1 面向对象的static
5.1.1 局部静态变量
static
修饰局部变量:该局部静态变量的生命周期在整个程序运行期间都有效,所有的文件都可以访问。
例如:
//example
#include<stdio.h>
int func(int a)
{
static int c = 2;
c += a;
return c;
}
int main()
{
int a = 1, b;
b = func(a++);
printf("b:%d", b);
b = func(a++);
printf("b:%d", b);
return 0;
}
在函数体内定义变量,变量的作用域仅限于该函数体的一次执行,因为当程序运行到该语句时在在栈上分配内存,函数该函数体运行完后,该变量的内存会被自动释放。这样,如果我们第二次使用改变量要在第一次使用的基础上时,就出现了问题。
static
关键字正好解决了这一问题,上面也提到过,static
关键字修饰的变量存储在全局数据区,可以一直在原来的技术上使用该局部静态变量。
局部静态变量有以下特点:
1 局部静态变量在全局数据区分配内存;
2 局部静态变量在程序执行到该变量的声明处时被首次初始化,以后使用不再初始化;
3 局部静态变量一般在声明处被初始化,如果没有显式初始化,会被默认初始化为0;
4 它始终在全局数据区,直到程序运行结束。但其作用域仍为局部作用域,当其所在函数或语句块结束时,其随之结束。
5.1.2 全局静态变量
static
修饰全局变量:该全局静态变量作用域只限于本文件,其他文件不能访问。也即在其他文件中定义一个相同名字的变量,编译器不会报错。
例如:
/*file1*/
#include<stdio.h>
static int age; //声明为外部变量
int main()
{
age = 19;
printf("I am %d years old", age);
return 0;
}
/*file2*/
#include<stdio.h>
extern int age; //声明为外部变量
int main()
{
age = 19;
printf("I am %d years old", age);
return 0;
}
这两个文件编译都没问题,但是运行的时候就会出现错误。将file1中的static int age;
改为int age;
之后,两个文件都可编译运行了。
所以,静态全局变量不能被其他文件引用。
C/C++中extern和static的更多相关文章
- 小胖说事28------iOS中extern,static和const差别和使用方法
通俗的讲: extern字段使用的时候,声明的变量为全局变量,都能够调用,也有这样一种比較狭义的说法:extern能够扩展一个类中的变量到还有一个类中: static声明的变量是静态变量,变量值改变过 ...
- C语言关键字register、extern、static、一些总结,及项目中使用的心得
首先介绍两个概念: 一.变量的生存周期: 变量从建立到撤销的时间段成变量的生存周期.静态变量,从变量产生到整个程序执行结束.当函数使用变量结束后,变量的存储空间依然存在,变量的值也会随着函数的对其的使 ...
- C++中extern “C”含义及extern、static关键字浅析
https://blog.csdn.net/bzhxuexi/article/details/31782445 1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C ...
- 链接(extern、static关键词\头文件\静态库\共享库)
原文链接:http://www.orlion.ga/781/ 一. 多目标文件的链接 假设有两个文件:stack.c: /* stack.c */ char stack[512]; int top = ...
- 【转载】C/C++中extern关键字详解
1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...
- C/C++中extern关键字解析
1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...
- C/C++中extern关键字详解
转自:http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html 1 基本解释:extern可以置于变量或者函数前,以标示变 ...
- IOS的变量前加extern和static字段
IOS的变量前加extern和static字段 前一阵子,做项目的时候到网上找Demo,打开运行的时候发现其中变量前有关键字extern和static,所以我研究了一下子 对于extern来说可以理解 ...
- C++中extern “C”含义深层探索
C++中extern “C”含义深层探索 extern “C” 是一个双向都需要用到的语法表示,就是说在cpp引用c头文件,或者c引用cpp文件时都需要用到.但extern “C” 永远只能在cpp引 ...
随机推荐
- Sublime 3基于python环境的使用
.Ctrl+Shift+R 自动调整格式 打开Sublime Text 新建一个Python的编译系统 { "cmd": ["C:\\python\\python.exe ...
- 如果裸写一个goroutine pool
引言 在上文中,我说到golang的原生http server处理client的connection的时候,每个connection起一个goroutine,这是一个相当粗暴的方法.为了感受更深一点, ...
- bzoj 3239 poj 2417 BSGS
BSGS算法,预处理出ϕ(c)−−−−√内的a的幂,每次再一块一块的往上找,转移时将b乘上逆元,哈希表里O(1)查询即可 #include<cstdio> #include<cstr ...
- jdbc 增删改查以及遇见的 数据库报错Can't get hostname for your address如何解决
最近开始复习以前学过的JDBC今天肝了一晚上 来睡睡回笼觉,长话短说 我们现在开始. 我们先写一个获取数据库连接的jdbc封装类 以后可以用 如果不是maven环境的话在src文件下新建一个db.pr ...
- JavaSE-管道流
1,)创建管道输出流PipedOutputStream pos和管道输入流PipedInputStream pis 2,)将pos和pis匹配,pos.connect(pis); 3,)将pos赋给信 ...
- appium在android 7.0真机上运行报错command failed shell:............ps:'uiautomator"的解决方式
appium版本:1_4_16 在CSDN中找到相关解决的方案,根据此解决方案顺利的解决了让人惆怅的问题,再次记录. 1.找到appium安装目录下的adb.js文件,目录为:Appium\node_ ...
- selenium IDE 使用方法整理
1.设置起始点(确定case从哪步开始执行),快捷键:S,效果图如下: 2.设置断点(case执行到添加断点处,将自动停止),快捷键:B,效果图如下: 3.设置判断点 如:百度输入ceshi,点 ...
- 前端教程(1)http协议的深刻理解
一 HTTP协议简介 作为学习前端开发的开始,我们必须搞明白以下几件事 1.什么是互联网 互联网=物理连接介质+互联网协议 2.互联网建立的目的? 数据传输打破地域限制,否则的话,我 ...
- 吴恩达深度学习笔记1-神经网络的编程基础(Basics of Neural Network programming)
一:二分类(Binary Classification) 逻辑回归是一个用于二分类(binary classification)的算法.在二分类问题中,我们的目标就是习得一个分类器,它以对象的特征向量 ...
- 深入理解OkHttp源码(一)——提交请求
本篇文章主要介绍OkHttp执行同步和异步请求的大体流程.主要流程如下图: 主要分析到getResponseWidthInterceptorChain方法,该方法为具体的根据请求获取响应部分,留着后面 ...