c语言寄存器头文件共用重复定义,嵌入式C语言实战开发(五)

一、关键字

1、register关键字

(1)register作用的实现原理?

计算机的三大组成部分:

aad47655a5474f2f42cd22601eff9577.png

CPU的三大组成部分:运算器、控制器、存储器

cache高速缓存器

存储器

寄存器

(2)为什么要把变量变为寄存器变量?(register关键字作用?)

经常被访问的变量我们就可以用register修饰为寄存器变量,请求编译器尽可能的将变量存在CPU的内部寄存器中,节省了CPU从内存中抓取数据的时间,从而提高了运行效率。

(3)使用register关键字应注意哪些?

register只能修饰局部变量,不能修饰全局变量和函数;

register修饰的变量不能通过取地址来获取寄存器变量;

register修饰的变量一定是CPU能接受的数据类型。

2、static关键字

(1)static关键字作用:

static修饰的变量全部保存在数据段的静态存储区,没有初始化的系统默认初始化为0;

static修饰静态局部变量,延长局部变量的生命周期,直至整个程序结束后释放。

static修饰全局变量,使得此全局变量只在本文件可见,不能在其他文件调用。

static修饰函数,使得此函数只在本文件调用,不能在其他文件调用。

(2)什么时候用static关键字?

可以重命名变量 、函数;

想让局部变量在程序结束后释放用static,我们要尽可能的少的使用全局变量,全局                    变量比较危险,对所有文件可见,可能在别的文件中发生更改。

想让全局变量、函数只在本文件中被调用,对函数、全局变量起保护作用。

3、extern关键字

extern关键字:(全局变量)外部声明,声明这个变量是在其他文件中定义的,声明时一定要标注变量的数据类型。

4、const关键字

const修饰变量,使变量成为只读变量。

比如:const int num = 5;

const 修饰num,num为只读变量,空间里的值可变,但是不能通过num这个变量名来修改这个空间的对应值。

举例:

(1)const int a = 10;

(2)int const a = 10;

(3)const int a[10] = {1,2,3,4,5,6,7,8,9,10};

(4)const int *p;

(5)int * const p;

(6)const struct devices dev[5];

(7)struct devices const * dev[5];

技巧:

将类型去掉;

看const修饰谁,谁的值就是不能更改的,是readonly的.

(1)去掉类型int变成了”const a = 10”,a的值就不能变了;

(2)去掉类型int变成了”const a = 10”,a的值就不能变了;

(3)去掉类型int变成了”const a[10]”,a数组里的值就不变;

(4)const修饰*p,去掉类型int变成了”const *P”,p所指向的空间的值就不变;

(5)const 修饰p,去掉类型int *变成”const p”,指针p里的值就不能改变,也就是说p不能再指向其他地址,但是p所指向的空间里的值是可变的;

(6)去掉类型struct devices变成”const dev[5]”,dev[5]数组里的值就不改变;

(7)这是一个devices结构体类型的指针数组,它就拥有5个devices结构体类型指针,每个指针指向一个devices结构体,const修饰*dev[5],去掉类型struct devices变成”const *dev[5]”,指针数组dev中每个元素指向的空间里的值不变。

const 使用注意事项:

(1)const修饰变量,一定要对变量做初始化;

(2)一般用const修饰函数形参,防止函数实现过程中修改形参的值。

5、typedef关键字

给数据类型重起名字;

作用:

(1)提高代码的移植性;

(2)方便在编程定义变量、方便编写程序;

(3)解释某些变量的作用,起到注释的作用。

拓展:

typedef与define区别:

1、执行时间:typedef在编译阶段有类型检查的功能;define是宏定义,在预处理阶段,只进行简单机械的字符串替换,不进行任何检查;

2、功能:typedef定义类型的别名,定义与平台无关的数据类型,与struct结合使用等等;define不止可以为类型起别名,还可以定义常量、变量、编译开关等;

3、作用域:typedef有自己的作用域;define没有作用域的限制,只要是之前定义过的宏,在以后的程序中都可以使用;

6、volatile关键字

(1)不会在两个操作之间把volatile变量缓存在寄存器当中,在多任务中,甚至stejmp环境下变量可能被其他程序改变,编译器无法知道,volatile就是告诉编译器这种情况的;

(2)不做常量合并,常量传播等优化;

(3)对volatile变量的读写不会被优化掉,如果你对一个变量赋值,但后面没用到,编译器常常可以忽略掉那个赋值操作,然而对Memory Mapped IO处理是不能这样优化的。

二、复合数据类型

1、struct结构体

作用:封装数据

#include

struct student

{

int id;

char name[20];

int age;

};

typedef struct student Stu;

int main()

{

struct student stu;

struct student *p_stu = &stu;

// p_stu->id = 1;

scanf("%d",&(p_stu->id));

printf("id = %d\n",p_stu->id);

strcpy(p_stu->name,"zhangsan");

printf("name = %s\n",p_stu->name);

return 0;

}

结构体数组:

#include

struct student

{

int id;

char name[20];

int age;

};

int main()

{

struct student stu_array[3];

int i;

for(i = 0; i < 3; i++)

{

scanf("%d",&(stu_array[i].id));

scanf("%s",stu_array[i].name);

scanf("%d",&(stu_array[i].age));

}

for(i = 0; i < 3; i++)

{

printf("%d\t",stu_array[i].id);

printf("%s\t",stu_array[i].name);

printf("%d\t",stu_array[i].age);

printf("\n");

}

return 0;

}

结构体注意事项:

结构体有字对齐、半字对齐

内存空间:相同类型放一起,减少内存空间

函数返回多个值:结构体封装or传出参数

2、union共用体

(1)与结构体区别:

43ee1f3c069cb84dd0cc5b2a635b46cc.png

d908898e4a754c44e4d0def4c949a3fd.png

共用体共用同一个空间,由最大的决定

cddd587601d514a5df6ffc03766112d4.png

20a88537479987fa3227366d3f717675.png

共用一个空间会产生值得覆盖;

应用:利用共用体测试操作系统是大端字节序还是小端字节序

e39fa166b3074ca535592af0dc78aa3f.png

#include

union judge_cpu

{

int num;

char ch;

};

int main()

{

union judge_cpu jcp;

jcp.num = 0x12345678;

int num = 0x12345678;

char *p = #

#if 0

if(jcp.ch == 0x78)

{

printf("small!\n");

}

else

{

printf("big!\n");

}

#endif

if(*p == 0x78)

{

printf("small\n");

}

else

{

printf("big\n");

}

return 0;

}

3、enum枚举

70f498dc05acd8e98884b2a924358a57.png

c79896d82a1b403d87e7b3477d2ff7c9.png

枚举的作用:

1、杜绝幻数,提高可读性;

2、需要大量的整数宏时,用枚举。

三、编译预处理

1、宏定义指令

宏定义主要避免幻数,因为数字本身没有意义,宏定义命名时要清晰的表明其用途

拓展:

#define宏定义与枚举的区别:

(1)#define宏常量是在预编译阶段进行简单的替换,枚举常量则是在编译的时候确定其值;

(2)一般在编译器里,可以调试枚举常量,但是不能调试宏常量;

(3)枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个。

定义宏函数:

#include

#define MAX(a,b) a > b ? a : b

int main()

{

int num = MAX(5,6);

return 0;

}

自定义函数与宏函数有什么区别:

(1)函数式宏定义省去了函数的调用、函数的返回、释放、传参等,提高运行效率。

(2)函数式宏定义不做语法检查不安全;

(3)函数安全,会做语法检查,但运行效率会低;

用编译时间换内存空间:宏函数

用内存空间换执行/运行时间:inline(修饰函数、内敛函数)

内置宏定义:

__LINE__打印所在行

__func__显示函数名

__TIME__显示时间

__DATA__显示日期

2、条件编译

#if 0   #endif

#if 1  #endif

#ifdef和#ifndef:防止头文件包含带来的重复定义

比如:a.h

#ifndef A_H

#define A_H

...

#endif

3、嵌入式中的死循环

(1)while(1)

{

}

(2)for(;;)

{

}

break :结束所有循环

continue:结束当次循环

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值