嵌入式C语言关键字(const、static、volitatile)

这篇具有很好参考价值的文章主要介绍了嵌入式C语言关键字(const、static、volitatile)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

const关键字

C语言中const修饰通常是用来声明常量,并声明常量的值不能修改。当涉及指针变量时情况就会变得更加有趣,需要特别注意。因为有两样东西都有可能成为常量—一种是用来限定指向的空间的值不可修改;另一种是限定指针不可修改。下面是几个声明的例子:

int 	*pi;			//pi是一个普通的指向整型的指针变量
int const *pci;			//const修饰的是指针指向的值,故不可修改它所指向的值
int *const cpi;			//const修饰的是指针,故不可修改指针

总结:const 修改的是数据类型是指针,则指针可修改;类型是变量,则变量可修改。

概念

在了解static关键字的用法之前,先需要了解C语言中的作用域、连接属性和存储类型的概念。

作用域

当变量在程序的某个部分被声明时,它只有在程序一定区域才能被访问。这个区域由标识符(变量)的作用域决定。
编译器可以确认4种不同类型的作用域–文件作用域、函数作用域、代码块作用域和原型作用域。标识符声明的位置决定它的作用域。

代码块作用域

位于一对花括号({})之间的所有语句称为一个代码块。任何在代码块的开始位置声明的标识符(变量)都具有代码块作用域(block scope)

int a;
int d(int e)
{
	int f;
	int g(int h);
	{
		int f,g,i;	// 当程序执行到这里,访问的是刚刚声明的f的变量
	}
	// 当程序执行到这里时,访问的是本代码块({})的变量f的值
}

文件作用域

任何在代码块之外声明的标识符都具有文件作用域,它表示这些标识符从它们的声明之处直到它所在的源文件结尾处都是可以访问的。

原型作用域

原型作用域只适用于在函数原型中声明的参数名。如int b(int c):参数c的作用域–原型作用域。

函数作用域

函数作用域简化为一条规则–一个函数中所有语句标签必须唯一。

链接属性

当组成一个程序的各个源文件分别被编译之后,所有的目标文件以及那些从一个或多个函数库中引用的函数链接在一起,形成可执行程序。然而,标识符的链接属性决定如何处理在不同文件中出现的标识符。标识符的作用域与它的链接属性有关,但这两个属性并不相同。
连接属性一共有3种-----external(外部)、internal(内部)和nohe(无)。
关键字external和static用于在声明中修改标识符的链接属性。如果某个声明在正常情况下具有external链接属性,在它前面上加上static关键字可以使它的链接属性变为internal。例如,如果下面这个声明这样书写:

static int b;

那么这个变量b就将为这个源文件私有。
注意:static 只对缺省值链接属性为external的声明才有改变链接属性的效果

储存类型

变量的存储类型是指储存变量值的内存类型。变量的储存类型决定变量何时创建、何时销毁以及它的值将保持多久。有三个地方可以用于存储变量:普通内存、运行时堆栈、硬件寄存器
变量的缺省存储类型取决于它的声明位置。凡是在任何代码块之外明的变量总是存储于静态内存中,也就是不属于堆栈的内存,这类变量称为静态(static)变量

在代码块内部声明的变量的缺省储存类型是自动的(automatic),也就是说它存储于堆栈中,称为自动变量。对于在代码块内部声明的变量,如果给它加上关键字static,可以使它的存储类型从自动变量变为静态。注意:修改变量的储存类型并不表示修改该变量的作用域,它仍然只能在该代码块的内部按名字访问。

关键字register用于自动变量的声明,提示它们应该储存于机器的硬件寄存器而不是内存中,这类变量称为寄存器变量。

static关键字

当用于不同的上下文环境时,static关键字具有不同的意见。很不幸的是给予程序新手带来混淆。本篇文章对static关键字作了总结,再加上后续的程序例子,应该能给予帮助你搞清static关键字的问题。

  1. 当static用于函数定义时,或用于代码块之外的变量声明时,static关键字用于修改标识符的链接属性,从external改为internal,但标识符存储类型和作用域不受影响。用这种方式声明函数或变量只能在声明它们的源文件中访问。
  2. 当static用于代码块内部的变量声明时,static关键字用于修改变量的存储类型,自动变量修改为静态变量,但变量的链接属性和作用域不受影响
   int 	a = 5;
   extern 	int	b;
   static 		int 	c;
   int function(int e)
   {
   	int 	f = 15;
   	register	int	b;
   	static		int	g;
   	extern		int 	a;
   	{
   		int 	e;
   		int		a;
   		extern	int	h;
   	}
   	{
   		int 	x;
   		int		e;
   	}
   }

static int prifunction(void)
{
   
}

变量a、b、c的存储类型为静态,表示它们并不是存储于堆栈中。

函数function的作用域从函数开始到文件结束。

参数e不具备链接属性,只能通过函数内部访问。它具备自动存储类型。由于与局部变量冲突,它的作用域是除了冲突e代码块之外的作用域

变量f、b、g声明局部变量,所以它们的作用域到函数结束为止。它们不具备连接属性,所以它们不能在函数的外部通过名字访问。g的存储类型是静态,所以它在程序的整个执行过程一直存在。

代码块中a、e声明为局部变量。它们具备自动存储类型,不具有链接属性,它们的作用域只在花括号{}内。

全局变量h在代码块内可以被访问。它具有external属性,存储于静态内存中。

代码块变量x、e创建局部变量(自动、无链接属性、作用域限于本代码块)

函数prifunction具有静态链接属性。静态链接属性可以防止它被这个源文件之外的任何函数调用。

volatile的作用

最重要的作用及示例:告诉编译器不能做任何优化
在嵌入式或单片机中,如果用volatile,compiler就不允许做任何的优化,从而保证程序的原意,这对嵌入式来讲非常重要

1. 易变的
变量保存在内存中,但为了提高运行速度,有时不从内存取值,而从cpu缓存/寄存器中取值。在嵌入式/或单片机开发中,这有时是很致命的。

volatile 定义变量后:假设有读、写两条语句,依次对同一个 volatile 变量进行操作,那么后一条的读操作不会直接使用前一条的写操作对应的 volatile 变量的寄存器内容,而是重新从内存中读取该 volatile 变量的值。
```
volatile int nNum = 0;  // 将nNum声明为volatile
int nSum = 0;
nNum = FunA();      // nNum被写入的新内容,其值会缓存在寄存器中
nSum = nNum + 1;    // 此处会从内存(而非寄存器)中读取nNum的值
```

2. 不可优化的
在 C/C++ 编程语言中,volatile 的第二个特性是“不可优化性”。

volatile 会告诉编译器,不要对 volatile 声明的变量进行各种激进的优化(甚至将变量直接消除),从而保证程序员写在代码中的指令一定会被执行。
上述描述的(部分)示例代码内容如下:

volatile int nNum;  // 将nNum声明为volatile
nNum = 1;    
printf("nNum is: %d", nNum);

在上述代码中,如果变量 nNum 没有声明为 volatile 类型,则编译器在编译过程中就会对其进行优化,可能直接使用常量“1”进行替换(这样优化之后,生成的汇编代码很简洁,执行时效率很高)。

而当使用 volatile 进行声明后,编译器则不会对其进行优化,nNum 变量仍旧存在,编译器会将该变量从内存中取出,放入寄存器之中,然后再调用 printf() 函数进行打印

3. 顺序执行的
在 C/C++ 编程语言中,volatile 的第三个特性是“顺序执行特性”,即能够保证 volatile 变量间的顺序性不会被编译器进行乱序优化。

C/C++ 编译器最基本优化原理:保证一段程序的输出,在优化前后无变化。为了对本特性进行深入了解,下面以两个变量(nNum1 和 nNum2)为例(既然存在“顺序执行”,那描述对象必然大于一个),介绍 volatile 的顺序执行特性,示例代码内容如下:

int nNum1;
int nNum2; 
nNum2 = nNum1 + 1;    // 语句1
nNum1 = 10;           // 语句2

在上述代码中:当 nNum1 和 nNum2 都没有使用 volatile 关键字进行修饰时,编译器会对“语句1”和“语句2”的执行顺序进行优化:即先执行“语句2”、再执行“语句1”;

当 nNum2 使用 volatile 关键字进行修饰时,编译器也可能会对“语句1”和“语句2”的执行顺序进行优化:即先执行“语句2”、再执行“语句1”;

当 nNum1 和 nNum2 都使用 volatile 关键字进行修饰时,编译器不会对“语句1”和“语句2”的执行顺序进行优化:即先执行“语句1”、再执行“语句2”;

说明:对一般程序来讲保证值一样即可,但对嵌入式来讲,执行顺序很重要,上述可通过观察代码的生成的汇编代码进行验证。文章来源地址https://www.toymoban.com/news/detail-463375.html

到了这里,关于嵌入式C语言关键字(const、static、volitatile)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C# const关键字学习

    你居然不知道const?今天在做项目的时候别人问我的,我确实不知道这个,今天我们就来一起学习一下const定义局部变量,这个对于常数变量非常的友好的,可以提高程序的运行效率,因为它是在编译时的操作,所以我们必须要学习一下,这不就是提

    2024年01月22日
    浏览(53)
  • C++系列:const关键字

    在学习C++时,const的知识点分散在书的各个章节。当我们尝试在编程时使用const时,总会感觉有一些细节被遗忘,因而不能得心应手地使用const。因此,本篇文章尝试着对const的做一些总结。参考书籍《C++ Primer Plus》 这里是我做的关于const的一些总结

    2024年03月09日
    浏览(48)
  • 详解const、static关键字

    目录   一、static 二、const 在c语言中: static是用来修饰变量和函数的         1.修饰局部变量——称为静态局部变量         2.修饰全局变量——称为静态全局变量         3.修饰函数——称为静态函数 有关内存相关知识补充: 程序的所有数据,也就是所有的

    2024年02月06日
    浏览(45)
  • 【C++】const关键字的详解!!

    💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃 个人主页 :阿然成长日记 👈点击可跳转 📆 个人专栏: 🔹数据结构与算法🔹C语言进阶 🚩 不能则学,不知则问,耻于问人,决无长进 🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍 const是永恒不

    2024年02月03日
    浏览(42)
  • ES6中let和const关键字与var关键字之间的区别?

    前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而又亲切的学习平台。在这个

    2024年02月09日
    浏览(54)
  • 重学C++系列之const与static关键字分析

            本篇幅讲解const与static,主要围绕在类的范围内叙述,包括作用和使用场景等。         1、const修饰的成员变量,成员变量初始化后不能再修改。         2、const修饰的成员函数,成员函数不可以修改成员变量,也不能间接修改。         3、static修饰的成员

    2024年02月15日
    浏览(46)
  • 在C++和C中static关键字的用法,在C++和C中const关键字的用法

    1、在C++和C中static的用法 答:static表示存储类型,修饰数据类型。在C语言中,static修饰局部变量,内存分配在静态区,生命周期延长,作用域不变。static修饰全局变量,内存分配在静态区,作用域被局限于本文件,不能被extern引用。static修饰函数,不能被exter

    2024年02月10日
    浏览(41)
  • static,const,volatile,extern,register关键字深入解析

    ✅作者简介:嵌入式入坑者,与大家一起加油,希望文章能够帮助各位!!!! 📃个人主页:@rivencode的个人主页 🔥系列专栏:玩转C语言 💬保持学习、保持热爱、认真分享、一起进步!! 我们都知道一个源文件要生成我们计算机课执行的文件要经过: 源文件(test.c)—预编

    2023年04月08日
    浏览(35)
  • 【C++】const、static关键字和构造函数初始化

    💗个人主页💗 ⭐个人专栏——C++学习⭐ 💫点击关注🤩一起学习C语言💯💫 目录 1. const修饰成员函数 1.1 语法格式 1.2 权限放大缩小 1.3 思考 1.4 解答 2. 再谈构造函数 2.1 构造函数体赋值 2.2 初始化列表 2.3 explicit 3. static成员 3.1 静态变量 3.2 静态函数 3.3 静态成员变量

    2024年02月19日
    浏览(46)
  • JS中var、let以及const关键字到底怎么用?

    在学习JS变量之后,初学者都避免不了都会一下子分不清这三个变量在代码块中的作用域范围,其实 const 简单理解它就是定义常量的,但是在实际开发中,我们却很常见它的身影。 说实话刚开始我也分不清他们的作用域范围,但是自己再去详细看一遍教程之后,其实发现还是

    2023年04月13日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包