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

相关内容

热门资讯

原创 4... 写在文章前的声明:在本文之前的说明:本文中所列的投资信息,只是一个对基金资产净值进行排行的客观描述,...
胜宏科技港股大涨49% 做完英... 记者 陈月芹 4月21日,全球AI算力板龙头胜宏科技(02476.HK)登陆港交所,上市首日股价大涨...
永赢基金:聚焦“科技新锐”,科... 数据来源:Wind,时间统计区间为2025/1/1-2026/4/21,指数过往表现不预示未来,不构...
五大阅读趋势显现!当当网发布2... 在第31个世界读书日即将来临之际及首个全民阅读活动周期间,当当网正式发布2026国民阅读洞察报告。 ...
业绩逐季回暖 老百姓大药房一季... 上证报中国证券网讯(记者 夏子航)4月22日晚,老百姓大药房发布2025年年报和2026年一季报。今...
中国20强城市大洗牌:苏州接近... 中国的城市经济竞争格局一直在变化,每年发布的GDP数据都会对城市经济实力进行重新排列。2025年榜又...
直击金宏气体股东会:预期年内氦... 《科创板日报》4月22日讯(记者 郭辉)金宏气体日前举行2025年度股东大会。会上该公司审议了公司年...
5月1日起,俄据悉将叫停哈萨克... 据行业消息人士透露,俄罗斯将于5月1日起停止经友谊管道转运哈萨克斯坦输往德国的石油,相关调整计划已送...
深化具身智能生态布局 京东携手... 4 月 22 日,京东与国内消费级人形机器人头部企业松延动力正式达成三年期战略合作。双方将围绕产品研...
原创 帮... 先问你一个问题,美伊停火今晚到期,按常理避险情绪该升温,黄金应该涨吧?结果恰恰相反——原油涨了,黄金...
300295、600889,将... 三六五网、南京化纤,将被*ST。 公司股票自4月23日开市起停牌一天,于4月24日开市起复牌并实施退...
能源大变天!外媒:羡慕中国的石... 这一次油价突破 110 美元的能源危机,着实魔幻。如果放在十年前,没人会相信中国能在这场风波中获利,...
黄金涨跌两难,现在还能上车吗? 中新网4月22日电(记者 左雨晴) 四月以来,美伊局势反复拉扯,美联储降息预期一变再变。黄金价格在4...
“我身体健康”,库克现身员工大... 当地时间4月21日,受苹果官宣CEO换届影响,公司股价盘中下探超2%,总市值失守4万亿美元关口,收盘...
库克留下一个悬念 工程师能否拯救创新节奏? 听筒Tech(ID:tingtongtech)原创 文 | 赵 森 ...
探索消费信贷与社交支付深度融合... 腾讯这一金融产品再添新功能,4月19日,北京商报记者注意到,微信分付灰度测试转账功能引发热议,在向微...
土耳其主要银行股指早盘下跌2% 每经AI快讯,4月20日,土耳其主要银行股指早盘下跌2%。 每日经济新闻
好用的OTA代运营源头厂家 在如今竞争激烈的酒旅行业中,OTA代运营服务成为了众多酒店、民宿提升竞争力的关键。但市场上的代运营厂...
成都五一出游全国热门第三 “五一”假期临近,同程旅行最新发布的《2026“五一”旅行趋势报告》显示,今年“五一”期间成都同时位...