第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关键字的用法

相关内容

热门资讯

阿里千问App全球首发点外卖、... 1月15日,阿里举行千问App发布会, 阿里巴巴(BABA.US)集团副总裁吴嘉宣布,千问App全面...
携程港股、美股放量跌近20% 【大河财立方消息】1月15日,携程港股、美股双双大跌。 截至发稿,港股携程集团跌幅18.53%,美股...
淳厚基金获国资入主!管理规模缩... 淳厚基金获得长宁国投入主,但是市场声誉遭遇重挫,机构投资者纷纷撤出。 文/每日财报 楚风 随着国有...
「死了么」爆火,1亿独居群体被... 「核心提示」 独居时代下的深层焦虑,让“死了么”迎来短暂流量狂欢。不过,这款低门槛应用,拿什么...
2025年我国跨境电商进出口2... 一、明星品牌 1、美国奢侈品零售商萨克斯环球申请破产保护 美国高端百货集团萨克斯环球(Saks Gl...
卫龙前CEO孙亦农入职大窑出任... 红星资本局1月15日消息,红星资本局从大窑处了解到,卫龙(09985.HK)前CEO孙亦农已加入大窑...
市场利好持续提振港股医药股 东... 财联社1月15日讯(编辑 胡家荣)今日港股医药板块迎来强劲反弹,多只个股表现亮眼。截至发稿,东曜药业...
技术派登顶!2026浙江危机公... 2026年危机公关行业正经历近十年来最深刻的范式革命。当抖音热搜的存活周期缩短至3小时、AI生成虚假...
雷军官宣今晚直播:与汽车媒体一... 2026年1月15日,小米创办人,董事长兼CEO雷军在社交媒体平台发文称,“上次直播后,很多网友希望...
阿里千问宣布接入淘宝、支付宝、... 1月15日,阿里千问App宣布全面接入淘宝、支付宝、淘宝闪购、飞猪、高德等阿里生态业务,在全球首先实...
黄金投资交易入门:定义与风险评... 黄金投资交易是以黄金为交易标的的金融投资行为,核心是通过把握黄金价格的波动规律,以低买高卖的方式赚取...
第六批高值医用耗材集采开标,涉... 图片来源:视觉中国 蓝鲸新闻1月14日讯(记者 屠俊)据国家医保局官微信息显示,1月13日,第六批国...
瑞银:中国AI不堆卡、重效率,... “中国AI行业不存在美国式泡沫,反而将在模型出海、应用爆发、算力替代三大主线迎来系统性机遇。”1月1...
小鹏汇天冲击港股IPO:低空经... 2026年刚刚开始,小鹏汇天秘密提交港股IPO申请的消息就不胫而走。 有知情人士透露,小鹏汽车已聘请...
原创 马... 这将是一段动荡的旅程。 一 几周前,美国德州特斯拉超级工厂内,马斯克接受一次特殊访谈,预言2026。...
梁文锋旗下幻方量化,去年收益率... 每经记者|杨建 每经编辑|何小桃 叶峰 2025年A股市场持续火热,百亿私募交出了怎样的成绩单?据...
宽基ETF规模大增的三大理由 2026年,A股市场开局向好。Wind资讯数据显示,截至1月14日,开年以来ETF总规模增长超220...
冬季护眼 “睛”彩相伴|武汉普... 冬季天气寒冷干燥,室内取暖设备的使用让空气湿度降低,加上户外活动减少、长时间近距离用眼成为常态,干眼...
白银首破92美元,金铜锡拉升创... 2026年开年以来,全球金属市场迎来新一轮狂欢。 1月14日亚太交易时段,现货白银(伦敦银现)史上首...