C语言中的extern,static和register的一些用法_在c语言程序中可以用 extern register-程序员宅基地

技术标签: C  static  c语言  extern  register  

在谈extern和static用法之前,我们首先要清楚了解一些基础概念。
linkage链接属性有三种:external, internal, none。C和指针给出的介绍如下:
Identifiers that  have no linkage are always individuals, that is, multiple declarations of the identifier  are always treated as separate and distinct entities.
Internal linkage means that all  declarations  of  the  identifier  within  one  source  file  refer  to  a  single  entity,  but  declarations  of  the  same  identifier  in  other  source files  refer to  different  entities. 
Finally, all references to an identifier with external linkage refer to the same entity. 
我们通过下面的代码片段来看看链接属性是怎么回事?
int b;
int c (int d)
{
     int e;
     int f (int g);
     ......
}
标识符b,c,f的链接属性为external,剩下的诸如d,e,g都是none。
记住一点函数名和定义在函数外面的默认链接属性为external,这意味着假如这段代码在a.c这个文件中,另一个文件的b.c能够访问到b,c,f。

而如果仅仅想让b,c,f只在当前文件a.c使用,不想被其他文件访问,这个时候我们的external和static就起作用了:The keywords extern and static are used in declarations to modify the linkage  of the identifiers being declared.
比如static int b;关键词static就将b的属性改为internal,这意味着其他文件不能访问到该文件a.c中的b了。
同理static int c (int d); static int f (int g);也是如此。
但是需要注意一点:static only has this effect in declarations whose default linkage is external.   

而extern用法更复杂一点, 在C和指针中这么描述它:it specifies  external linkage for an identifier and is used to get access to an entity that is defined  elsewhere.我们通过下面的代码来解释这句话
static int i;
int fun ()
{
     int j;
     extern int k;
     extern int i;
}
在声明中将k指定为external链接属性,这使得fun函数能够访问到声明在其他源文件的中变量k。
另外一点是函数里面的exern int i并不能改变第一次定义时候 (static int i) 的链接属性。
When extern is used on the first declaration in the source file for an identifier, it  specifies  that  the  identifier  has  external  linkage.  When  used  on  the  second  or  subsequent declarations of an identifier, however, the keyword does not change the  linkage specified by the first declaration. 


下面我们再来看看存储类型(存储地址),书上给出的定义是The storage class of a variable refers to the type of memory in which the variable’s  value is stored. The storage class of a variable determines when it is created and  destroyed and how long it will retain its value. There are three possible places to store  variables:  in  ordinary  memory,  on  the  runtime  stack,  and  in  hardware  registers.
 一个变量默认的存储类型是由它声明的地方决定。
Variables declared outside of any blocks are always stored in static memory, that is, in  memory that is not part of the stack. There is no way to specify any other storage class  for these variables. Static variables are created before the program begins to run and  exist throughout its entire execution. They retain whatever value they were assigned  until a different value is assigned or until the program completes. 
The default storage class for variables declared within a block is automatic, that  is, on the stack. There is a keyword auto, but it is rarely used because it doesn’t change  the default. Automatic variables are created just before the program execution enters  the block in which they were declared, and they are discarded just as execution leaves  that block. If the block is executed several times, as in the case of a function that is  called repeatedly, new copies of the automatic variables are created each time. We therefore say  that automatic variables disappear at the end of a block; they generally will not have  their previous values the next time the block is entered.

但是如果变量声明在block内的话,用static可以改变它的存储类型,由auto变为static。此时这个变量的生存周期就变为整个程序,而非仅在它所声明的语句块内。但是改变存储类型并不改变它的作用域 ,只有在块内才可以访问它。我们通过一段代码来理解它。
#include <stdio.h>
void fun()
{
    static int times = 0;
    times++;
    printf("函数执行次数为%d\n", times);   
}

int main()
{
    int i = 0;
    for (i = 0; i < 5; i++)
        fun();
    //printf("times=%d\n", times);不能使用times([Error] 'times' undeclared (first use in this function))
    return 0;     
}
结果是:
函数执行次数为1
函数执行次数为2
函数执行次数为3
函数执行次数为4
函数执行次数为5
注意一点:函数的形参不能声明为static因为参数要在栈上传递来支持递归(recursion).

最后我们来看看register这个关键词,书上给出的定义:the  register  keyword  may  be  used  on  declarations  of  automatic  variables to indicate that they should be stored in the machine’s hardware registers  rather than in memory.Register variables are created and destroyed at the same time as automatic  variables, but there is some additional work needed. 
为什么要有register变量呢?主要是寄存器比内存访问速度快,更加有效。然而寄存器个数是有限的,因此编译器可以忽视这个关键词,这意味着如果有很多变量声明为register只有之前的一部分会放到寄存器中。因此你可以选择一些经常被使用的变量放在寄存器中来提高效率。
在一个使用寄存器变量的函数返回前,这些寄存器之前的存储的值必须恢复,确保调用者的寄存器变量未被破坏,许多机器使用运行时候堆栈来完成这个任务。当函数开始执行时候,它把需要使用的所有寄存器内存都保存在堆栈,当函数返回时候,这些纸在复制回寄存器中。在许多机器的硬件实现中,并不为寄存器指定地址。

总结:
static用于函数定义时,或者代码块之外的变量声明,static用于修改标识符的链接属性从external到internal,但标识符的存储类型和作用域不受影响,用这种方式声明的函数或变量只能在声明它们的源文件中访问。

static用于块内的变量声明,它用于修改变量的存储类型,从auto变为static,但链接属性和作用域不受影响。用这种方式声明的变量在程序执行前创建,并在整个程序执行期间一直存在,而非执行时创建,执行完毕销毁。

具有external链接属性的实体称为全局实体(global)所有源文件的所有函数都可以访问,只要变量并非声明于代码块内或函数定义内,它默认为external。当变量声明于代码块内,在它前面加extern使得它所引用的是全局变量。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xy913741894/article/details/52213297

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Python 攻克移动开发失败!_beeware-程序员宅基地

文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

推荐文章

热门文章

相关标签