笔记 嵌入式C语言

	***when to do? how to do? why to do?***

2-1 GCC的使用及其常用选项介绍

1 GCC(GNU C Compiler)

	翻译官 翻译组织。
	随着GCC支持的语言越来越多,它的名称变成了GNU Compiler Collection。GCC按照后缀名的不同,调用翻译组织中不同的翻译官。
	gcc -o   output
	gcc -o 输出的文件名 输入文件名,实例如下所示。
	gcc -v -o

在这里插入图片描述

扩充:
在这里插入图片描述
在Linux系统中,返回值0代表成功,非0代表不成功。

2 C语言编译过程

	C语言编译过程:预处理,编译,汇编,链接。
	预处理:替换。【gcc -E】

在这里插入图片描述

	编译:【gcc -S】

在这里插入图片描述

	汇编:【gcc -c】

在这里插入图片描述

	链接:链接系统标准库。【gcc -o】		

在这里插入图片描述

	Q1:define include是关键字吗?
	A1:define include 是在预处理阶段处理的,不是在编译阶段处理的,所以不是关键字。

3 C语言常见错误举例

	1,预处理错误:
	#include "name":" ",双引号是自定义的头文件(当前目录下)。
	#include <name>:< >,尖括号是系统库的头文件。
	not find错误:gcc -I 跟查找头文件的目录。
	编译错误:语法错误,;,{ }
	链接错误:
	原材料不够(undefined references to "fun"):寻找标签是否实现了,链接时是否加入一起链接。
	或多了(multiple definition of "fun"):多次实现了标签,只保留一个标签的实现。

4 预处理的使用

	#include	包含头文件
	#define	宏 替换,不进行语法检查
		#define 宏名 宏体 加括号	
	#ifdef #else #endif	 条件编译
	预定义宏
	  _FUNCTION_:函数名
	  _LINE_:行号
	  _FILE_:文件名
	扩充:gcc -D:gcc -DABC === #define ABC

在这里插入图片描述
宏展开下的#、##:
#:字符串化
##:连接符号
#define ABC(x) #x
#define ABC(x) day##x

2-2 C语言常用关键字及运算符操作

1 关键字

编译器预先定义了一定意义的字符串。32个关键字。		

01 杂项

sizeof:编译器给我们查看内存空间的一个工具。任何环境都可以实现。
	int a;
	printf("the a is %d\n",sizeof(a));
return:返回的概念。

02 数据类型

C操作对象:资源/内存{内存类型的资源,LCD缓存、LED灯}
C语言如何描述这些资源的属性?
		资源属性【大小】;限制内存的大小,关键字。
数据类型:
	char:
		硬件芯片的最小单位:bit	1	0
		软件操作的最小单位(1B == 8bit):char a;
		应用场景:硬件处理的最小单位。
	int:
		大小:根据编译器来决定,32bit为4B。
		编译器最优的处理大小:系统一个周期,所能接收的最大的处理单位,int。
		整型常量:
	long、short:特殊长度的限制符。
	unsigned、signed:数据类型的限制标志,有无符号。默认为有符号数。
		无符号:数据
		有符号:数字
		内存空间的最高字节,是符号位 还是数据
	float、double:
		大小:float 4B  double  8B
		内存存在形式:
	void:声明标志,语义符。

03 自定义数据类型

C编译器默认定义的内存分配不符合实际资源的形式。自定义 = 基本元素的集合。
struct:结构体,元素之间的和。递增累加顺序。
	struct myabc{
		unsigned int a;
		unsigned int b;
		unsigned int c;
		unsigned int d;
	};
	struct myabc mybuf;
	----------------------------
	顺序有要求。
union:共用体,共用起始地址的一段内存。应用于技巧型代码。
	union myabc{
		char a;
		int b;
	};
	union myabc abc;
enum:enumerate---列举,被命名的整形常数集合。
	enum 枚举类型{常量列表};
	enum week{
		Monday = 0, Tuesday = 1, Wednesday = 2,
		Thursday,Friday,Saturday,Sunday
	};
typedef:数据类型的别名。
	xxx_t:typedef
	int a;	a是一个int类型的变量
	typedef int a_t;a是一个int类型的外号
	a_t mysize;

04 逻辑结构

CPU顺序执行程序。分支和循环
if、else:
switch、case、default:多分支
	switch(整形数字)
do、while、for:循环
	for:次数
	while:条件
continue、break、goto:
	goto:函数内部跳转使用较安全

05 类型修饰符

对内存资源存放位置的限定,资源属性中位置的限定
auto:默认情况,分配的内存可读可写的区域。
	区域如果在{ },栈空间
register:定义一些快速访问的变量。编译器会尽量的安排CPU的寄存器去存放这个A,如果寄存器不足时,A还是放在存储器中。&这个符号对register不起作用
	auto int a:
	register int a:限制变量定义在寄存器的修饰符
	----------------------------------------
	内存(存储器)	寄存器
	0x100			R0,R2
static:静态
	应用场景:修饰3种数据。
	1)函数内部的变量
	2)函数外部的变量,即全局变量
	3)函数的修饰符
const:常量的定义,只读的变量
extern:外部声明
volatile:告知编译器编译方法的关键字,不优化编译。修饰变量值的修改,不仅仅可以通过软件,也可以通过其他方式(硬件外部的用户)。

2 运算符

01 算术操作运算

+、-、*、/、%

02 逻辑运算

真 假,二值性,返回的结果是0或1。
||、&&、>、 >=、 <、 <=、 !、 ? :

03 位运算

<<、 >>、 &、 |、 ^、~
	左移,乘法,符号变量无关;
	右移,除法,符号变量有关。右移时,负数最高位填1,正数最高位填0。
	&:取出,清零器;
		a = (a | (0x1<<5));	SET
	|:保留,设置为高电平的方法
		a = (a & ~(0x1<<5));	RESET
	^:数据交换
		int a = 20,b = 30;
		***a = a ^ b; b = a ^ b; a = a ^ b;***
		a = 30, b = 20

04 赋值运算

=、+=、-=、&=、...

05 内存访问符号

( )、[ ]、{ }、->、.、&、*

3 逻辑操作

 顺序执行, 分支执行, 循环执行

2-3 C语言内存空间的使用

1 指针

01 指针概述

指针概述:内存类型资源地址、门牌号的代名词
指针:
指针变量:存放指针这个概念的盒子
C语言编译器对指针这个特殊的概念,有两个疑问?
	1,分配一个盒子,盒子要多大?	
		在32位系统中,指针就4个字节
	2,盒子里存放的地址,所指向的内存读取方法是什么?
		char *p;int *p;
	注:指针指向内存空间,一定要保证合法性。

在这里插入图片描述
在这里插入图片描述

02 指针+修饰符

const:常量,只读【不可变】
	内存属性:1,内存操作的大小。2,内存的变化性,可读可写。
	const char *p :字符串 “helloworld" 	内容不可更改
	char * const p :硬件资源 LCD 	内容可以更改
	const char * const p:ROM

在这里插入图片描述
在这里插入图片描述

volatile:防止优化指向内存地址。只和硬件有关。
	char *p;
	volatile char *p;
	*p == 0x10;
typedef:
	char *name_t:name_t是一个指针,指向了一个char类型的内存;
	typedef char *name_t:name_t是一个指针类型的名称,指向了一个char类型的内存。
	name_t abc;

03 指针+运算符

++、--、+、-:
	int *p = xxx	[0x12]
	p + n 	[0x12 + n * (sizeof(*p))]
	指针的加法运算,实际上加的是一个单位,单位的大小可以使用sizeof(p[0])
	p++ 	p--,更新地址
[ ]:地址变量
	变量名[n],n:ID 标签。地址内容的标签访问方式,取出标签里的内存值
逻辑操作符:>= <= == !=
	
	1,跟一个特殊值进行比较	0x0:地址的无效值,结束标志
	2,指针必须是同类型的比较才有意义

在这里插入图片描述
在这里插入图片描述

04 多级指针

int **p;
存放地址的地址空间
p[m] == NULL --->结束了

2 数组

内存分配的一种形式。

01 数组的定义

定义一个空间:
	1,大小
	2,读取方式
数据类型 数组名[m] m的作用域,只在申请的时候起作用
数组名是一个常量符号,一定不要放到=的左边
	如char buf[10] = "abc";
	buf = "hello world";	×
	int a[100];
注意:指针是变量,数组的地址的标签,常量

02 数组空间的初始化

空间的赋值
	按照标签逐一处理
----》空间定义时,就告知编译器的初始化情况,空间的第一次赋值,初始化操作
	第二次内存初始化,赋值?	逐一处理
int a[10] = 空间
C语言本身,CPU内部本身一般不支持空间和空间的拷贝
-------------------------------------------------
数组空间的初始化和变量的初始化本质不同,尤其是嵌入式的裸机开发中,空间的初始化往往需要库函数的辅助。
举例:
	char buf[10] = "abc";
	buf[2] = 'e'; √	buf指向变量,可以对其进行修改
	char *p = "abc";
	p[2] = 'e'; ×	p指向常量,不可以对变量进行修改		
字符串的重要属性,结尾一定有个'\0'。
strcpy,strncpy:
	一块空间,当成字符空间,提供了一套字符拷贝函数
字符拷贝函数的原则:
	内存空间和内存空间的逐一赋值功能的一个封装体
	一旦空间中出现了0这个特殊值,函数就即将结束。
strcpy():char buf[10] = ”abc";strcpy(buf,"hello world");
非字符空间:
	字符空间:ASCII码编码来解码的空间,---》给人看
	非字符空间:数据采集 0x00 - 0xff
	拷贝三要素:src,dest,个数
memcpy:
	int buf[10];
	int sensor_buf[100];
	memcpy(buf,sensor_buf,10*sizeof(int));

03 指针与数组

指针数组:
	int a[100];
	char * a[100];	sizeof(a) = 100 * 4;	存放地址的数组
注:char **a;可以理解为指针数组。		

3 结构体、共用体

01 字节对齐

效率,牺牲一点空间换取时间效率
最终结构体的大小,一定是4的倍数
结构体里成员变量顺序不一致,也会影响它的大小
注:32位系统,按照4个字节对齐,实际根据系统默认设置值

4 内存分布图

内存的属性:
1,大小
2,在哪里
编译--》汇编--》链接

在这里插入图片描述

01 堆空间

运行时,可以自由,自我管理的分配和释放的空间,生存周期是由程序员来决定。
分配:
	malloc(),一旦成功,返回分配好的地址给我们,只需要接收,对于这个新地址的读法,由程序员灵活把握,输入参数指定分配的大小,单位就是B。
	char *p
	p = (char *)malloc(100);
	if(p == NULL){
		error
	}
释放:
	free(p);

02 栈空间

运行时,函数内部使用的变量,函数一旦返回就释放,生存周期是函数内。

03 只读空间

静态空间,整个程序结束时释放内存,生存周期最长。

5 段错误分析

2-4 C语言函数的使用

1 函数概述

一堆代码的集合,用一个标签去描述它。 复用化
函数 数组,函数具备3要素:
	1,函数名	(地址)
	2,输入参数
	3,返回值
	在定义函数时,必须将3要素告知编译器。
	int fun(int,int,char)
	{xxx}
	如何用指针保存函数?
		char *p;
		char(*p) [10];
		int (*p) (int,int,char);	

2 输入参数

承上启下的功能。
调用者:函数名(要传递的数据)	//实参
被调者:函数的具体实现
	函数的返回值 函数名(接收的数据)	//形参
	{
		xxx
	}
实参传递给形参
传递的形式:拷贝

01 值传递

上层调用者 保护自己空间值不被修改的能力

02 地址传递

上层,调用者 让下层 子函数 修改自己空间值的方式
作用:
	1,修改
	2,空间传递
		2.1 子函数看看空间里的情况	
		2.2 子函数反向修改上层空间的内容
类似结构体这样的空间,函数与函数之间调用关系---》
连续空间的传递

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

03 连续空间的传递

1,数组
	数组名---标签
	实参:
		int abc[10];
		fun(abc)
	形参:
		void fun(int *p)	
2,结构体
	结构体变量
	优先选择使用右边的指针方式。

在这里插入图片描述

3 返回值

提供启下功能的一种表现形式。

在这里插入图片描述

2-5 常见面试题目讲解

1 嵌入式工程师必备0x10道题目

嵌入式工程师必备0x10道题目

01 宏定义

用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECOND_OF_YEAR	(365*24*3600)UL

02 数据声明

用变量a给出下面的定义:
1)一个整型数
	int a;
2)一个指向整型数的指针
	int *a;
3)一个指向指针的指针,它指向的指针是指向一个整型数
	int **a;
4)一个有10个整型数的数组
	int a[10];
5)一个有10个指针的数组,该指针是指向一个整型数的
	int *a[10];
6)一个指向有10个整型数组的指针
	int [10] *a; ---> int (*a)[10];
7)一个指向函数的指针,该函数有一个整形参数并返回一个整型数
	int fun(int) *a;---> int (*a)(int);
8)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
	int (*a[10])(int);

03 修饰符的使用总结

关键字static的作用是什么?
	1)修饰局部变量:
	默认局部变量在栈空间存在,生存期比较短
	局部静态化,局部变量在静态数据段中保存,生存期非常长
	2)修饰全局变量:
	防止重命名,限制变量名只在本文件内起作用
	3)修饰全局函数
	防止重命名,限制该函数名只在本文件内起作用
关键字const有什么含义?
	C:只读,建议性 不具备强制性 不等于常量
	C++:常量
关键字volatil有什么含义?并给出三个不同的例子。
	防止C语言编译器的优化。
		它修饰的变量,该变量的修改可能通过第三方来修改。

04 位操作

a |= (0x1<<3);
a &= ~(0x1<<3);

05 访问固定内存位置

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值