第4章 C语言高级的关键字
admin
2024-01-21 00:21:52
0

文章目录

    • 文档配套视频讲解链接地址
    • 第04章 关键字
      • 4.1 static 关键字的深入理解
        • 1. static 关键字修饰局部变量
        • 2. static 关键字修饰全局变量
        • 3. static 关键字修饰函数
        • 4. extern 关键字的深入理解
        • 5. volatile 关键字的深入理解

文档配套视频讲解链接地址

  1. 腾讯课堂视频链接地址 : 18_关键字_static关键字
  2. 腾讯课堂视频链接地址 : 19_关键字_extern关键字
  3. 腾讯课堂视频链接地址 : 20_关键字_volatile关键字

第04章 关键字

4.1 static 关键字的深入理解

1. static 关键字修饰局部变量

  • 延长局部变量的生存期, 由原来的动态生存期变为静态生存期, 这个变量的值只能被初始化一次 , 值可以继承 。
  • 实例35
  • static 修饰局部变量,延长生存期
  • 源文件
linux@ubuntu:~/work/emb2207/03-chigh/35-static$ tree
.
├── build
├── CMakeLists.txt
├── main.c
└── src├── beep.c├── beep.h├── led.c└── led.h2 directories, 6 files
  • 源代码
linux@ubuntu:~/work/emb2207/03-chigh/35-static$ cat main.c 
#include  #include "led.h"
#include "beep.h"int main(int argc, char const *argv[])
{led_on(); led_off();char * p = beep_on();printf("*p=%s\n",p);p = beep_on();printf("*p=%s\n",p);p = beep_on();printf("*p=%s\n",p);return 0;
}
linux@ubuntu:~/work/emb2207/03-chigh/35-static$ cat src/beep.c 
#include   char * beep_on(void)
{static int a = 10 ; // static 修饰局部变量, 只能被初始化一次  , 值可以保持 static int b ; // static 修饰的局部变量 没有赋初始值, 初始值为0 static char buf[100]={"hello world!!"}; a++; b++;printf("beep_on:a=%d\n",a);printf("beep_on:b=%d\n",b);printf("beep_on\n");return  buf ; 
}int beep_off(void) 
{printf("beep_off\n");return 0; 
}
linux@ubuntu:~/work/emb2207/03-chigh/35-static$ cat src/beep.h
#ifndef _BEEP_H
#define _BEEP_Hchar * beep_on(void);   // 函数的声明 
int beep_off(void) ; // 函数的声明 #endif  linux@ubuntu:~/work/emb2207/03-chigh/35-static$ cat CMakeLists.txt 
cmake_minimum_required (VERSION 2.8)      project (main)include_directories(. src)    # 添加标准头文件的搜索路径 , 程序中可以使用 include <>aux_source_directory(.   SRC_LIST1)    # 获取目录下的源文件 
aux_source_directory(src SRC_LIST2)    # 获取目录下的源文件 add_executable(main ${SRC_LIST1} ${SRC_LIST2}) linux@ubuntu:~/work/emb2207/03-chigh/35-static$ 
  • 运行结果
linux@ubuntu:~/work/emb2207/03-chigh/35-static/build$ cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/linux/work/emb2207/03-chigh/35-static/build
linux@ubuntu:~/work/emb2207/03-chigh/35-static/build$ make 
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/src/beep.c.o
[ 50%] Linking C executable main
[100%] Built target main
linux@ubuntu:~/work/emb2207/03-chigh/35-static/build$ ./main 
led_on
led_off
beep_on:a=11
beep_on:b=1
beep_on
*p=hello world!!
beep_on:a=12
beep_on:b=2
beep_on
*p=hello world!!
beep_on:a=13
beep_on:b=3
beep_on
*p=hello world!!

2. static 关键字修饰全局变量

  • static 修饰全局变量用来限定全局变量的作用域 , 让这个全局变量的作用域只能在本文件内, 不能超越本文件
  • 目的是为了在多文件的工程中, 是为了解决变量重名的问题
  • 例如 ,全局变量重名的问题
linux@ubuntu:~/work/emb2207/03-chigh/36-static/build$ make 
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
[ 50%] Building C object CMakeFiles/main.dir/src/beep.c.o
[ 75%] Building C object CMakeFiles/main.dir/src/led.c.o
[100%] Linking C executable main
CMakeFiles/main.dir/src/led.c.o:(.data+0x0): `temp'被多次定义
CMakeFiles/main.dir/src/beep.c.o:(.data+0x0):第一次在此定义
collect2: error: ld returned 1 exit status
CMakeFiles/main.dir/build.make:146: recipe for target 'main' failed
make[2]: *** [main] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/main.dir/all' failed
make[1]: *** [CMakeFiles/main.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
  • 解决变量重名的问题, 就需要使用static 限定全局变量的作用域, 限定在本文件内。
  • 实例36
  • 源文件
linux@ubuntu:~/work/emb2207/03-chigh/36-static/build$ tree ..
..
├── build
├── CMakeLists.txt
├── main.c
└── src├── beep.c├── beep.h├── led.c└── led.h2 directories, 6 files
  • 源代码
linux@ubuntu:~/work/emb2207/03-chigh/36-static$ cat src/beep.c 
#include   // 全局变量在工程中是唯一的变量, 如果出现重名就报错
static int  temp = 100;  // temp 的作用域就是在文件内 , 不会超出本文件, 不会出现工程中变量重名了 
char * beep_on(void)
{static int a = 10 ; // static 修饰局部变量, 只能被初始化一次  , 值可以保持 static int b ; // static 修饰的局部变量 没有赋初始值, 初始值为0 static char buf[100]={"hello world!!"}; a++; b++;printf("beep_on:a=%d\n",a);printf("beep_on:b=%d\n",b);printf("beep_on\n");return  buf ; 
}int beep_off(void) 
{printf("beep_off\n");return 0; 
}
linux@ubuntu:~/work/emb2207/03-chigh/36-static$ cat src/led.c 
#include   static int temp = 100; // 全局变量在工程中是唯一的变量, 如果出现重名就报错
int led_on(void)
{printf("led_on\n");return 0 ; 
}int led_off(void) 
{printf("led_off\n");return 0; 
}
  • 运行结果
linux@ubuntu:~/work/emb2207/03-chigh/36-static/build$ make 
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/src/beep.c.o
[ 50%] Building C object CMakeFiles/main.dir/src/led.c.o
[ 75%] Linking C executable main
[100%] Built target main
linux@ubuntu:~/work/emb2207/03-chigh/36-static/build$ 

3. static 关键字修饰函数

  • static 修饰函数用来限定函数的作用域 , 让这个函数的作用域只能在本文件内, 不能超越本文件
  • 目的是为了在多文件的工程中, 是为了解决函数重名的问题
  • 例如 ,函数重名的问题
linux@ubuntu:~/work/emb2207/03-chigh/37-static/build$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
[ 50%] Building C object CMakeFiles/main.dir/src/beep.c.o
[ 75%] Building C object CMakeFiles/main.dir/src/led.c.o
[100%] Linking C executable main
CMakeFiles/main.dir/src/led.c.o:在函数‘display’中:
led.c:(.text+0x2e): `display'被多次定义
CMakeFiles/main.dir/src/beep.c.o:beep.c:(.text+0x80):第一次在此定义
collect2: error: ld returned 1 exit status
CMakeFiles/main.dir/build.make:146: recipe for target 'main' failed
make[2]: *** [main] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/main.dir/all' failed
make[1]: *** [CMakeFiles/main.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
  • 解决函数重名的问题, 就需要使用static 限定函数的作用域, 限定在本文件内。
  • 实例37
  • 解决工程中函数重名的方法
  • 源文件
linux@ubuntu:~/work/emb2207/03-chigh/37-static/build$ tree ..
..
├── build
├── CMakeLists.txt
├── main.c
└── src├── beep.c├── beep.h├── led.c└── led.h2 directories, 6 files
  • 源代码
linux@ubuntu:~/work/emb2207/03-chigh/37-static$ cat src/beep.c 
#include   // 全局变量在工程中是唯一的变量, 如果出现重名就报错
static int  temp = 100;  // temp 的作用域就是在文件内 , 不会超出本文件, 不会出现工程中变量重名了 
char * beep_on(void)
{static int a = 10 ; // static 修饰局部变量, 只能被初始化一次  , 值可以保持 static int b ; // static 修饰的局部变量 没有赋初始值, 初始值为0 static char buf[100]={"hello world!!"}; a++; b++;printf("beep_on:a=%d\n",a);printf("beep_on:b=%d\n",b);printf("beep_on\n");return  buf ; 
}int beep_off(void) 
{printf("beep_off\n");return 0; 
}static int display(void)
{printf("display\n");return 0;
}
linux@ubuntu:~/work/emb2207/03-chigh/37-static$ cat src/led.c 
#include   static int temp = 100; // 全局变量在工程中是唯一的变量, 如果出现重名就报错
int led_on(void)
{printf("led_on\n");return 0 ; 
}int led_off(void) 
{printf("led_off\n");return 0; 
}static int display(void)
{printf("display\n");return 0;
}
linux@ubuntu:~/work/emb2207/03-chigh/37-static$ 
  • 运行结果
linux@ubuntu:~/work/emb2207/03-chigh/37-static/build$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
[ 50%] Building C object CMakeFiles/main.dir/src/beep.c.o
[ 75%] Building C object CMakeFiles/main.dir/src/led.c.o
[100%] Linking C executable main
[100%] Built target main
linux@ubuntu:~/work/emb2207/03-chigh/37-static/build$ 

4. extern 关键字的深入理解

  • 主要的作用是声明函数或变量,告诉编译器在这用了这个变量或函数, 定义不在, 在别的文件, 不要报错
  • 类似理解为提前声明, 防止编译报错
  • 例如, 在程序中使用别的文件定义的全局变量, 会报错
linux@ubuntu:~/work/emb2207/03-chigh/38-extern/build$ make 
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
/home/linux/work/emb2207/03-chigh/38-extern/main.c: In function ‘main’:
/home/linux/work/emb2207/03-chigh/38-extern/main.c:20:5: error: ‘led_count’ undeclared (first use in this function); did you mean ‘led_on’?led_count++;^~~~~~~~~led_on
/home/linux/work/emb2207/03-chigh/38-extern/main.c:20:5: note: each undeclared identifier is reported only once for each function it appears in
/home/linux/work/emb2207/03-chigh/38-extern/main.c:21:5: warning: implicit declaration of function ‘pirntf’; did you mean ‘printf’? [-Wimplicit-function-declaration]pirntf("led_count=%d\n",led_count);^~~~~~printf
CMakeFiles/main.dir/build.make:62: recipe for target 'CMakeFiles/main.dir/main.c.o' failed
make[2]: *** [CMakeFiles/main.dir/main.c.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/main.dir/all' failed
make[1]: *** [CMakeFiles/main.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
linux@ubuntu:~/work/emb2207/03-chigh/38-extern/build$ 
  • 解决变量未定义的办法是使用extern 去声明这个全局变量
  • 声明可以放在头文件当中也可以放在main.c 中
  • 实例38
  • 原文件
linux@ubuntu:~/work/emb2207/03-chigh/38-extern/build$ tree ..
..
├── build
├── CMakeLists.txt
├── main.c
└── src├── beep.c├── beep.h├── led.c└── led.h2 directories, 6 files
  • 源代码
linux@ubuntu:~/work/emb2207/03-chigh/38-extern$ cat main.c 
#include #include "led.h"
#include "beep.h"// 这里不是定义, 因此不能赋初始值, 只是声明, 告诉编译器这个变量在别的文件中定义了, 这里只是声明
// 编译不要报未找到变量
extern int led_count; // 不能赋初始值, 一旦赋值就变成定义变量了
extern int display_beep(void); // 函数的声明, 可以不写在.h 文件中 
int main(int argc, char const *argv[])
{led_on();led_off();char *p = beep_on();printf("*p=%s\n", p);p = beep_on();printf("*p=%s\n", p);p = beep_on();printf("*p=%s\n", p);led_count++;printf("led_count=%d\n", led_count);display_beep();return 0;
}
linux@ubuntu:~/work/emb2207/03-chigh/38-extern$ cat src/beep.c 
#include int led_count = 1; // 定义一个全局变量 , 这个全局变量想在main.c中使用// 全局变量在工程中是唯一的变量, 如果出现重名就报错
static int temp = 100; // temp 的作用域就是在文件内 , 不会超出本文件, 不会出现工程中变量重名了
char *beep_on(void)
{static int a = 10; // static 修饰局部变量, 只能被初始化一次  , 值可以保持static int b;      // static 修饰的局部变量 没有赋初始值, 初始值为0static char buf[100] = {"hello world!!"};a++;b++;printf("beep_on:a=%d\n", a);printf("beep_on:b=%d\n", b);printf("beep_on\n");return buf;
}int beep_off(void)
{printf("beep_off\n");return 0;
}static int display(void)
{printf("display\n");return 0;
}int display_beep(void)
{printf("display_beep\n");return 0;
}
linux@ubuntu:~/work/emb2207/03-chigh/38-extern$ cat src/led.c 
#include   static int temp = 100; // 全局变量在工程中是唯一的变量, 如果出现重名就报错
int led_on(void)
{printf("led_on\n");return 0 ; 
}int led_off(void) 
{printf("led_off\n");return 0; 
}static int display(void)
{printf("display\n");return 0;
}
  • extern 声明变量或函数去解决未定义的函数或变量
linux@ubuntu:~/work/emb2207/03-chigh/38-extern/build$ make 
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
[ 50%] Linking C executable main
[100%] Built target main
linux@ubuntu:~/work/emb2207/03-chigh/38-extern/build$ 
  • 总结 , 在有的时候extern 在声明函数或变量时可以省略不写, 也是起到了声明的作用。

5. volatile 关键字的深入理解

  • 防止编译器优化代码, 出现逻辑问题, 加上这个关键字后, 编译器对volatile修饰的代码不再优化。
  • volatile 关键字(keywords)是一种类型修饰符,volatile 的英文翻译过来是 “易变的” 。用volatile 声明类型变量的时候,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用 volatile 进行声明,则编译器将对所声明的语句进行优化。即 volatile 关键字影响编译器编译的结果,用 volatile 声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错。
  • 例如 , 告诉compiler不能做任何优化
// 比如要往某一地址送两指令:
int *ip =...; //设备地址
*ip = 1; //第一个指令
*ip = 2; //第二个指令//以上程序被compiler可能做优化为:
int *ip = ...;
*ip = 1; //第一个指令 , 可能被编译器优化掉了 , 硬件上写两次是有意义的
*ip = 2;//结果第一个指令丢失。如果用volatile, compiler就不允许做任何的优化,从而保证程序的原意:
volatile int *ip = ...;
*ip = 1;
*ip = 2;
//即使你要compiler做优化,它也不会把两次付值语句间化为一,它只能做其它的优化。
  • volatile实际应用
#define     __O     volatile             /*!< Defines 'write only' permissions */
#define     __IO    volatile             /*!< Defines 'read / write' permissions *//* following defines should be used for structure members */
#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */
#define     __OM     volatile            /*! Defines 'write only' structure member permissions */
#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */typedef __IO int32_t  vs32;
typedef __IO int16_t  vs16;
typedef __IO int8_t   vs8;typedef __I int32_t vsc32;  /*!< Read Only */
typedef __I int16_t vsc16;  /*!< Read Only */
typedef __I int8_t vsc8;   /*!< Read Only */typedef struct
{__IM  uint32_t CPUID;                  /*!< Offset: 0x000 (R/ )  CPUID Base Register */__IOM uint32_t ICSR;                   /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register */__IOM uint32_t VTOR;                   /*!< Offset: 0x008 (R/W)  Vector Table Offset Register */__IOM uint32_t AIRCR;                  /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register */__IOM uint32_t SCR;                    /*!< Offset: 0x010 (R/W)  System Control Register */__IOM uint32_t CCR;                    /*!< Offset: 0x014 (R/W)  Configuration Control Register */__IOM uint8_t  SHP[12U];               /*!< Offset: 0x018 (R/W)  System Handlers Priority Registers (4-7, 8-11, 12-15) */__IOM uint32_t SHCSR;                  /*!< Offset: 0x024 (R/W)  System Handler Control and State Register */__IOM uint32_t CFSR;                   /*!< Offset: 0x028 (R/W)  Configurable Fault Status Register */__IOM uint32_t HFSR;                   /*!< Offset: 0x02C (R/W)  HardFault Status Register */__IOM uint32_t DFSR;                   /*!< Offset: 0x030 (R/W)  Debug Fault Status Register */__IOM uint32_t MMFAR;                  /*!< Offset: 0x034 (R/W)  MemManage Fault Address Register */__IOM uint32_t BFAR;                   /*!< Offset: 0x038 (R/W)  BusFault Address Register */__IOM uint32_t AFSR;                   /*!< Offset: 0x03C (R/W)  Auxiliary Fault Status Register */__IM  uint32_t PFR[2U];                /*!< Offset: 0x040 (R/ )  Processor Feature Register */__IM  uint32_t DFR;                    /*!< Offset: 0x048 (R/ )  Debug Feature Register */__IM  uint32_t ADR;                    /*!< Offset: 0x04C (R/ )  Auxiliary Feature Register */__IM  uint32_t MMFR[4U];               /*!< Offset: 0x050 (R/ )  Memory Model Feature Register */__IM  uint32_t ISAR[5U];               /*!< Offset: 0x060 (R/ )  Instruction Set Attributes Register */uint32_t RESERVED0[5U];__IOM uint32_t CPACR;                  /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register */
} SCB_Type;
  • 什么情况下使用volatile 这个关键字, 什么是易变变量
  • 多线程访问时, 要使用这个关键字修饰线程间共享的变量
  • 硬件的寄存器访问时, 因为硬件也是易变的, 也需要使用volatile这个关键字
  • 深入理解, 参考资料 volatile关键字的用法

相关内容

热门资讯

ST中装:公司主要银行账户已全... 证券之星消息,ST中装(002822)06月24日在投资者关系平台上答复投资者关心的问题。 投资者提...
2026年开窗机行业趋势与战略... 一、开篇引言:市场格局重塑下的选择逻辑 步入2026年,全球建筑智能化与绿色节能政策的叠加驱动,使开...
资金全面转向科技,传统消费企业... 近期 A 股出现明显风格切换,老牌消费资金持续流出,机构与传统上市公司纷纷加码半导体、算力赛道。 先...
合肥保利翡翠天奕具体交房时间是... 对于众多购房者而言,“合肥保利翡翠天奕具体交房时间是什么时候?能按时交房吗?”是心中最关切的问题。根...
港股风向标|恒指连续杀跌后企稳... 财联社6月24日讯(编辑 冯轶)今日港股短线企稳,三大指数集体收涨。截至收盘,恒生指数涨0.33%,...
瑞众人寿达州中支被罚17万,涉... 蓝鲸新闻6月24日讯,近日,国家金融监督管理总局达州监管分局发布行政处罚决定书,剑指瑞众人寿保险有限...
美国最担心的事还是来了,中国加... 最近这段时间,国际金融圈子里有一笔账,算得各家央行心里都不太踏实。 截至2026年春季,美国国债总规...
马斯克,不是万亿富豪了 资产历史性超过万亿美元不到两周,特斯拉、SpaceX掌门人埃隆·马斯克的身价近日快速下跌。 据中新经...
突发!金价跌破4000美元,近... 每经记者:杜宇 记者|杜宇 编辑|何小桃 杜恒峰 校对|金冥羽 金银价格大跳水。 6月24日晚,现货...
粗粮吃越多越好?很多糖友吃错升... 控糖圈一直流传多吃粗粮稳血糖,不少糖友直接三餐全吃粗粮、顿顿杂粮,不仅胃胀消化不良,餐后血糖反而不降...
持续大跌!刚刚,黄金跌破400... 潮新闻客户端 记者 吴恩慧 6月24日,贵金属再次大跌。 截至发稿时,现货黄金大跌近3%,跌破400...
2026年安徽白酒代加工/贴牌... 一、行业背景与痛点引入 白酒代加工领域正经历结构性变革。据行业观察,2025年至2026年,中小酒企...
曾在次贷危机中取得900%收益... 来源:环球市场播报 对冲基金经理Lee Robinson在全球金融危机期间曾凭借及时做空美国次级抵押...
基金“业界良心”又吹哨?杨东旗... 图片来源:图虫创意 “A股大量的热门股票,未来极有可能跌掉八成乃至九成以上,我们不敢再参与了。”6月...
浙江稠州商业银行护航“两司两员... 近年来,随着平台经济、共享经济蓬勃兴起,货车司机、网约车司机、快递员、外卖配送员(以下简称:两司两员...
IPO研究 | 中国日均Tok... 瑞财经 王敏 6月22日,河南鑫宇光科技股份有限公司(以下简称“鑫宇科技”)北交所IPO获受理,保荐...
IPO定向松绑,难道硬科技无动... 睡前和大家唠两句,最近市场藏着不少容易被忽略的动向,值得好好捋捋。本篇为大家准备了4条要闻,都是实打...
Kalshi首席执行官称预测交... 来源:环球市场播报 核心要点 Kalshi首席执行官塔雷克・曼苏尔在消费者新闻与商业频道《财经早...
韩国科技股暴跌点燃全球抛售潮 在全世界范围内, AI资本神话遭遇微观与宏观的双重审视 文|《财经》特约撰稿人 金焱 发自华盛顿 编...
审计署通报!中国银行逃税23.... 6月23日,审计署发布《国务院关于2025年度中央预算执行和其他财政收支的审计工作报告》,在报告中的...