嵌入式C语言基础 学习总结 笔记day_01
C语言学习笔记分享
第一节 C语言概述
1. 计算器的组成
1.1 冯·诺伊曼架构 MCU MPU
定义:冯·诺伊曼模型,也称冯·诺伊曼架构,是现代计算机的基础,分为输入设备,输出设备,存储器,处理器和总线五部分。
输入设备:让用户向计算机输入数据,如键盘,鼠标等。
输出设备:让计算机将处理过的数据展示给用户,如显示器,打印机等。
==IO接口:输出: 引脚输出高低电平、RXD\TXD通讯==
==输入:引脚接受高低电平、RXD\TXD通讯==
存储器:用于存储数据和指令,在冯·诺伊曼模型中,数据和指令存储在同一内存中。 8G 16G 32G 64G
内存(RAM ==内存条==):运行内存,程序运行过程中所产生数据的存储区,掉电丢失数据
工作内容:程序运行过程中所产生数据的存储区,快速的调用计算机内部的各种资源
==程序运行所需要的,C语言中变量存储的位置==
外存(ROM)(==硬盘==):存储空间,掉电不丢失
工作内容:存储工作数据;如:照片、视频、文档等
==掉电不丢失文件,照片、视频、文档==
CPU 缓存: 是计算机内部速度最快的
工作内容:用于CPU高速处理用的 -> 3M 18M
处理器:负责执行指令和处理数据,由==算术逻辑单元==和==控制单元组成==。总线:连接各个部分,负责数据传输。
1.2 程序语言发展过程
程序:一组计算机能识别和执行的指令
只要让计算机执行这个程序,计算机就会自动地、有条不紊地进行工作
计算机的一切操作都是由程序控制的,离开程序,计算机将一事无成
机器语言(由0和1组成的指令)
==打纸带==
==编程麻烦、移植性不高==
汇编语言(用英文字母和数字表示指令)
==移植性不高==
高级语言(接近于人的自然语言和数学语言)
==正常人类可以看懂 C语言==
面向过程的语言 (非结构化的语言、结构化语言)
==C语言==
==结构体(创造数据集)、函数(创造操作集 )==
函数的优点, 提高代码的复用性 在一定程度上 提高代码的复用性
面向对象的语言 ==new 对象==
==C++、JAVA==
==类:你的对象==
在C++中
人 数据:身高、体重、姓名 -> 类
人 操作:走、跑、跳 -> 类
在C语言中
人 数据:身高、体重、姓名 -> 结构体中
人 操作:走、跑、跳 -> 函数中
2. 源程序格式
c语言的源码文件由 .c 或 .h后缀名结尾
.C 文件为 可编译文件
.h 文件为 声明文件 库文件
.h 文件中 有一个张三的名字
通过 .c文件 调用张三
C语言程序的基本结构:
1.预处理指令:这些编译器指令,通常放在程序的开头,
#include <stdio.h>。预处理器指令以#字符开始,最常见的#include,用于包含其他的头文件。2.函数:C程序中至少包含一个函数,即
main()函数。main()函数是程序执行的起点。此外,一个C程序中可以包含其他的函数,这些函数可以自己定义也可以是从库中调用。3.变量:变量用于存储数据。在C语言中,每个变量都有特有类型。
4.语句&表达式:语句是执行特定任务的语句,如赋值语句、调用函数等,表达式则是计算产生值的计算公式。
5.注释:注释用于解释程序的功能,对代码进行解释和描述。在C语言中,注释可以用
/* 注释内容 */或者//注释内容来书写。
实例程序
#include <stdio.h> //预处理指令
// stdio.h 标注输入输出库 用于管理 系统中的关于文件 / 设备的输入输出
/* 这是一个简单的C程序 */
int main() //函数开始
{
int a = 10; //定义变量和赋值语句
printf("Hello World"); //语句:调用printf函数
int b = a + 50 + 60 + b;
for(int i ; i < 10 ; i++ )
break;
return 0; //语句:返回,结束main函数
} //函数结束
// 预处理指令 --> 预处理指令 以 # 开头的语句 include(调库) define(宏替换)
// 主函数 ---> C语言程序的入口,程序开始执行就会直接执行 main函数 是主调函数
// 函数 ---> C语言的函数就是定义操作 可以是主调函数,也可以是被调函数
// 定义变量 ---> 定义你需要的变量
// 输出语句 ---> 例如 printf puts putc 输出到屏幕终端
// 输入语句 ---> 例如 scanf getchar 从键盘读取
// 条件判断语句 ----> if switch
// 循环语句 ----> while for
// 运算语句 ----> 运算符 变量计算
// 返回语句 ----> 返回值, 当函数接受后,需要返回给主调函数或者系统一个返回值 void 不需要返回,或者 -->return ;
// return 语句会直接退出函数 不会继续运行
// exit 直接退出程序
3. 编译原理
3.1 gcc 命令的使用
gcc 是交叉编译器 x86 ARM 8位
编译命令:gcc [选项] 源文件 [选项] [目标文件]
运行命令:./目标文件
显示全部警告 -Wall
警告和错误的区别:
警告 某些警告在一定程度上可以忽略 编译会进行编译并输出 可执行文件
错误 不行 错误必须全部解决,编译器才能对你的源码进行编译
==警告和错误都不能排除逻辑性问题,可以使用调式工具GDB来调试代码的逻辑性问题==
错误和警告都是针对语法的,不针对逻辑性错误
如果有多文件交叉使用,需要将多个源文件一起编译;例如 gcc 1.c 2.c 3.c -o test
3.1 C程序编译阶段
gcc 编译流程
1. 预处理 阶段
处理程序的头文件展开、宏定义替换、删注释等内容,生成.i文件;
gcc -E hello.c -o hello.i
==不报错,执行预处理指令,删注释 , 导入头文件==
2. 编译 阶段
检查代码的规范性,是否有语法错误,将代码翻译成汇编语言;生成 .s文件
gcc -S hello.i -o hello.s
3. 汇编 阶段
将.s文件转换成==二进制目标文件==,生成.o文件
gcc -c hello.s -o hello.o
4. 链接 阶段
将程序中所用到的库加载到代码中,一般路径是/usr/lib;生成最终的可执行文件
gcc hello.o -o hello
如果不选择选项和目标文件,则会默认生成一个a.out的可执行文件
4. 数据的表达
计算机中数据的存储分为两大部分:数值型与非数值型数据存储
4.1 数值型数据的表示方式
4.1.1 十进制
前导符:无
特点:逢十进一,每一位上的数字范围:【0-9】
4.1.2、二进制
前导符:0b 单片机中,用于控制io口 | 寄存器
特点:逢二进一,每一位上的数字范围:0/1
4.1.3、八进制
前导符:0
特点:逢八进一,每一位上的数字范围:【0-7】
4.1.4、十六进制
前导符:0x 表示地址
特点:逢16进一,每一位上的数字范围:【0-9】,A-F对应10-15
4.2 非数值型数据的表示方式
字符串 、字符 、视频、音频、照片
字符 : 字符由 符号 、字母、转义 'R' 'N' 'G' 数值转换成 字符 通过 ascii 值
字符串 : 字符串串 多个字符组成在一起 "RNG"
视频、音频、照片 RGB码
ASCII码表:每一个字符都有对应的数值
4.3 原码、反码、补码
源码 十进制正常转换 二进制 后的 数值
反码 十进制 的取反 符号位 不变
补码 反码 + 1
原码、反码和补码是用于表示和存储二进制有符号整数的方式。它们都用最高位(通常是左边的位)表示符号,0表示正,1表示负。
我们需要使用C语言来存储一个 负数 就确定这个负数所占用的 内存大小
原码、反码、补码 对 正数 不起作用
原码 正数所表达的 二级制 如果是负数 则符号位 为 1
-1 的源码 1000 0001
反码 源码的基础上 除了符号位不变 其他为取反
-1 的源码 1111 1110
补码 反码的基础上 + 1
-1 的源码 1111 1111
%d 4字节 有符号 输出
#u 4字节 无符号 输出
4.4 有符号和无符号的问题
有符号数,包含了负数
无符号数,只有正数
无符号的时候 0 ~ 255
有符号的时候,0~255 进行拆分 127 ~ -128
==无符号 char 0 ~ 255==
==有符号 char -128 ~ 127==
第二节 C语言基础
1. 关键字和标识符
2.1 关键字
编译器中规定好的一些有特殊含义的单词,可以直接使用
数据类型 void char short int long signed unsigned float double struct union enum
数据修饰符 const static extern register volatile auto
改类型名称 typedef
运算符 sizeof
结构语句 if else switch case default goto for while do break continue return
注意:关键字严格区分大小写,并且全是小写的。
2.2 标识符
系统判断变量名和函数名、常量名
自己取得名字,如==变量名、函数名==等
命名时要符合标识符的命名规范:
1、由字母、数字、下划线所组成
2、不能以数字开头
3、不能和关键字重名
4、不能和其他标识符重名
命名时,尽量做到见起名知其意,使用驼峰命名法
ShuaiGe_PNG
GPIO_Pin
GPIO_Mode_Out
通过 ==大小写== ==下划线== 来划分 每个单词的分割
2. 数据类型
代表在C语言中的存储空间大小 存储空间的类型 浮点数、整数
整型
字符型 -> char 1字节
整型 int 4字节
short int -> 短 整型 2字节
long int -> 长 整型 8字节
unsigned 无符号
浮点型
单精度浮点型 float 4 字节
双精度浮点型 double 8 字节
long double 16字节
==sizeof() 用于测量变量空间大小==
printf( "%ld" , sizeof(char) );
char ch = 0;
printf( "%ld" , sizeof(ch) );
#include <stdio.h>
int main(int argc, char const *argv[])
{
char ch = 0;
short int in_1 = 0;
unsigned int u_in = 0;
int in = 0;
long int l_in = 0;
long long l_l = 0;
// char ch 定义了一个变量 其变量名称 为 ch 变量类型为 char (字符型)
printf("size ch = %ld\n" , sizeof(ch)); // char ==> 1 字节
printf("size in_1 = %ld\n" , sizeof(in_1)); // short int ==> 2 字节
printf("size u_in = %ld\n" , sizeof(u_in)); // unsigned int ==> 4 字节 32
printf("size in = %ld\n" , sizeof(in)); // int ==> 4 字节 32
printf("size l_in = %ld\n" , sizeof(l_in)); // long int ==> 8 字节 32
printf("size l_l = %ld\n" , sizeof(l_l)); // long long ==> 8 字节 32
// printf 是打印到终端
// %d 用于打印 整数
// %ld 用于打印 长整形
// \n 用于换行
// sizeof 用于测量变量的所占空间大小 并返回
// 1 比特 = 1 个位 数据表达最小单位
// 8 比特 = 1 b 字节
return 0;
// return 函数运行接受之后,进行返回
}
3. 存储类型
3.1 常量的分类
3.1.1 整型常量
前缀 占位符 举例
二进制 0b 无 0b1010
八进制 0 %#o 024
十进制 无 %d 131
十六进制 0x %#x 0xDB4
3.1.2 浮点型常量
小数也是常量
3.1.3 字符型常量
‘a’ = 97
3.2 常量的声明
3.2.1 #define 宏定义
可以通过宏定义的方式来进行声明一个变量
#define MAX_SIZE 255
#include <stdio.h>
#define MAX_SIZE 255
// #define 宏替换语句
// MAX_SIZE 常量的常量名
// 255
// 意思: 将255 替换成 MAX_SIZE
// 需要注意的是不是赋值
int main(int argc, char const *argv[])
{
int num_1 = 0;
num_1 = MAX_SIZE + 20;
printf("MAX_SIZE + 20 = %d" , num_1 );
// MAX_SIZE = MAX_SIZE + 20;
// 这里报错的原因是 常量不能被更改
return 0;
}
3.2.2 const修饰符
使用const 可以修饰变量为常量
const 在进行声明变量的时候,可以让变量在执行的过程中 不被改变
const int num = 50;
const 用于修饰常量 ---> 将变量 num 变成常量
int 修饰int类型的常量
num 常量名
= 50; 赋值为50
3.2.3 const 和 #define 的区别
#define 是无脑替换
const 只能用于修饰变量 让变量成为常量
#define 没有在 ==栈区== 创建空间
const 创建的空间 ,空间大小由常量类型决定
4. 运算符
| 运算符类别 | 运算符 |
|---|---|
| 算术运算符 | +,-,*,/,% |
| 赋值运算符 | =,+=,-=,*=,/=,%= |
| 关系运算符 | == , ! = , > , < ,> = ,< = |
| 逻辑运算符 | &&,|| ,! |
| 位运算符 | &,|,^,~,<<,>> |
| 条件运算符 ==是c语言中唯一一个三目运算符== | ? : |
| 自增自减运算符 | ++,-- |
| 逗号运算符 ==不常用== | , |
| 指针运算符 | * & |
| sizeof运算符 ==不是函数== | sizeof |
4.1 算术运算符
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
printf("a + b = %d\n", a + b); // 30
printf("a - b = %d\n", a - b); // -10
printf("a * b = %d\n", a * b); // 200
printf("b / a = %d\n", b / a); // 2
printf("b %% a = %d\n", b % a); // 0
return 0;
}
4.2 赋值运算符
#include <stdio.h>
int main() {
int a = 10;
a += 20; // a = a + 20
printf("a = %d\n", a); // 30
a -= 5; // a = a - 5
printf("a = %d\n", a); // 25
a *= 2; // a = a * 2
printf("a = %d\n", a); // 50
a /= 10; // a = a / 10
printf("a = %d\n", a); // 5
a %= 3; // a = a % 3
printf("a = %d\n", a); // 2
return 0;
}
4.3 关系运算符
关系运算符在C语言中用于比较两个值,结果为一个布尔值(0或1)。如果比较的条件成立,那么结果为1,否则为0。以下是C语言中的关系运算符:
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
printf("a > b: %d\n", a > b); // 0 (false)
printf("a < b: %d\n", a < b); // 1 (true)
printf("a >= b: %d\n", a >= b); // 0 (false)
printf("a <= b: %d\n", a <= b); // 1 (true)
printf("a == b: %d\n", a == b); // 0 (false)
printf("a != b: %d\n", a != b); // 1 (true)
return 0;
}
4.4 逻辑运算符
逻辑运算符用于链接和操作布尔值(真或假,即1或0)。C语言中的逻辑运算符包括“与”(&&),“或”(||)和“非”(!)。以下是这些运算符的解释:
&& 逻辑与 全1 得1
|| 逻辑 或 有1 得1
! 逻辑 非 取反
**1.**逻辑与运算符(&&):当两边的操作数都为真(非零)时,结果才为真。如果任一操作数为假(即零),结果就为假。
例如:
int a = 1;
int b = 0;
int result = a || b; // result 的值为 1,因为 a 为非零
**2.**逻辑或运算符(||):只要两个操作数中的任一操作数为真,结果就为真。只有当两个操作数都为假,结果才为假。
例如:
int a = 1;
int b = 0;
int result = a || b; // result 的值为 1,因为 a 为非零
**3.**逻辑非运算符(!):这是一个单目运算符,对一个布尔值进行取反操作。如果操作数为真,结果为假,反之亦然。
例如:
int a = 1;
int result = !a; // result 的值为 0,因为 a 为真(非零)
示例:
#include <stdio.h>
int main() {
int a = 1;
int b = 0;
printf("a && b: %d\n", a && b); // 0 (false)
printf("a || b: %d\n", a || b); // 1 (true)
printf("!a: %d\n", !a); // 0 (false)
printf("!b: %d\n", !b); // 1 (true)
return 0;
}
4.5 位运算符
按位于: 按每一位进行与运算
位运算符直接对整数在内存中的二进制位进行操作。这些运算符包括:按位与(&)、按位或(|)、按位异或(^)、取反(~)、左移(<<)和右移(>>)。下面详细解释每一种:
**1.**按位与运算符(&):如果两个相应的二进制位都为1,则结果为1,否则为0。
例如:
int a = 60; // 60的二进制是 0011 1100
int b = 13; // 13的二进制是 0000 1101
int result = a & b; // result 的值为 12,二进制为 0000 1100
**2.**按位或运算符(|):如果两个相应的二进制位中至少有一个1,则结果为1,否则为0。
例如:
int a = 60; // 60的二进制是 0011 1100
int b = 13; // 13的二进制是 0000 1101
int result = a | b; // result 的值为 61,二进制为 0011 1101
**3.**按位 异或运算符(^): 相同为0 不同为1
例如:
int a = 60; // 60的二进制是 0011 1100
int b = 13; // 13的二进制是 0000 1101
int result = a ^ b; // result 的值为 49,二进制为 0011 0001
**4.**取反运算符(~):对数的每一位取反,0变1,1变0。
例如:
int a = 60; // 60的二进制是 0011 1100
int result = ~a; // result 的值为 -61,二进制为 1100 0011
**5.**左移运算符(<<):把位向左移动指定的位数,右边用0填充。
例如:
int a = 15; // 15的二进制是 0000 1111
int result = a << 2; // result 的值为 60,二进制为 0011 1100
**6.**右移运算符(>>):把位向右移动指定的位数,左边的空位如何填充取决于数字的符号==(正数左边填充0,负数左边填充1)==。
例如:
int a = 15; // 15的二进制是 0000 1111
int result = a >> 2; // result 的值为 3,二进制为 0000 0011
实例:
#include <stdio.h>
int main() {
int a = 60; /* 60 = 0011 1100 */
int b = 13; /* 13 = 0000 1101 */
int result;
result = a & b; /* 12 = 0000 1100 */
printf("result = a & b: %d\n", result);
result = a | b; /* 61 = 0011 1101 */
printf("result = a | b: %d\n", result);
result = a ^ b; /* 49 = 0011 0001 */
printf("result = a ^ b: %d\n", result);
result = ~a; /*-61 = 1100 0011 */
printf("result = ~a: %d\n", result);
result = a << 2; /* 240 = 1111 0000 */
printf("result = a << 2: %d\n", result);
result = a >> 2; /* 15 = 0000 1111 */
printf("result = a >> 2: %d\n", result);
return 0;
}
4.6 条件运算符
条件运算符也称为三元运算符,其格式为:
条件表达式 ? 表达式1 : 表达式2
三元运算符的执行过程是这样的:
- 首先,程序会计算条件表达式的值
- 如果条件表达式的值为真(非0),那么程序会计算调大是1
例如:
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int max = a > b ? a : b;
//首先判断 a > b ? a : b
printf("最大的数是:%d\n", max);
return 0;
}
#include <stdio.h>
int main() {
int a = 10;
int b = (a == 1) ? 20 : 30;
printf("b is %d\n", b); // b is 30
return 0;
}
4.7 自增自减运算符
C语言中的自增(++)和自减(--)运算符用于增加或减少变量的值。这些运算符有前缀和后缀两种形式,对应着不同的操作顺序。
- 前缀自增/自减:先进行自增/自减操作,然后再进行其他操作。例如,
++a或--a。 - 后缀自增/自减:先进行其他操作,然后再进行自增/自减操作。例如,
a++或a--。
int a = 10;
int b = ++a; // 先增加a的值,然后赋值给b。此时a和b都为11。
a = 10; // 重置a的值为10
b = a++; // 先将a的值赋给b,然后再增加a的值。此时a为11,b为10。
4.8 逗号运算符
逗号运算符在C语言中被用来链接两个或更多的独立的表达式,从而使它们能在一行内执行。逗号运算符有两个主要的特点:
- 从左至右的顺序执行:逗号运算符的所有操作数都按从左到右的顺序进行计算。
- 返回值:逗号运算符的返回值是最后一个表达式的值。
让我们看一个简单的例子来更好地理解这个概念:
#include <stdio.h>
int main() {
int a, b;
a = (a = 10000 , b=4, b+2);
printf("a 的值是 %d\n", a );
return 0;
}
在上述代码中,逗号运算符将两个表达式b=4和b+2链接在一起。首先,b=4被执行,然后执行b+2,最后,b+2的结果被赋给变量a。因此,a的最终值为6。
请注意,虽然逗号运算符可以将多个表达式链接在一起,但过度使用可能会使代码难以理解和维护。在编程时,最好尽可能地保持代码的清晰和简洁。
4.9 指针运算符
在C语言中,我们主要有4个指针运算符,它们是:
-
*(解引用运算符):这个运算符返回指针所指向的值。例如,如果p是一个指向整数的指针,并且该整数的值是10,那么*p将返回10。int a = 10; int *p = &a; printf("%d\n", *p); // 输出: 10 -
&(取地址运算符):这个运算符返回变量的内存地址。例如,如果a是一个整数,那么&a将返回这个整数在内存中的地址。int a = 10; printf("%p\n", &a); // 输出: a在内存中的地址 -
++和--(自增和自减运算符):这些运算符用于改变指针的值,使其指向下一个或上一个内存位置。如果p是一个指向整数的指针,并且整数占用4个字节,那么p++将使p指向内存中的下一个整数,而p--将使p指向内存中的上一个整数。int arr[] = {10, 20, 30}; int *p = arr; printf("%d\n", *p); // 输出: 10 p++; printf("%d\n", *p); // 输出: 20 -
指针比较运算符:这些包括
==、!=、<、>、<=、>=。它们可以用来比较两个指针的值(即它们所指向的内存地址)。int a = 10, b = 20; int *p1 = &a, *p2 = &b; if (p1 != p2) { printf("p1 and p2 point to different locations.\n"); }
以上就是C语言中关于指针的主要运算符。
4.10 sizeof运算符
sizeof运算符是C语言中的一种单目运算符,用于获取一个特定类型或特定对象的大小(以字节为单位)。其可以应用于任何数据类型,包括基本类型(如int、char、double等)、派生类型(如数组、指针等)和自定义类型(如结构体、联合等)。
以下是sizeof运算符的一些使用示例:
#include <stdio.h>
int main()
{
int a;
double b;
char c[10];
printf("Size of int: %lu\n", sizeof(a)); // 输出: Size of int: 4
printf("Size of double: %lu\n", sizeof(b)); // 输出: Size of double: 8
printf("Size of char[10]: %lu\n", sizeof(c)); // 输出: Size of char[10]: 10
return 0;
}
在上述代码中,
sizeof(a)返回变量a的大小(以字节为单位),sizeof(b)返回变量b的大小,sizeof(c)返回数组c的大小。需要注意的是,
sizeof运算符返回的是size_t类型的值,这是一种无符号整型数据类型,所以在printf函数中应该使用%lu(代表长无符号整型)来格式化输出。另外,也可以使用
sizeof运算符来获取一个类型的大小,而不仅仅是变量的大小。例如,sizeof(int)将返回int类型的大小,sizeof(double)将返回double类型的大小。
练习1:
通过位操作 操作一个 32 位的数据对其进行如下操作
1、一次性操作两位 对 这个32位数据中的 5位 和 6位 变成11
2、一次性操作两位 对 这个32位数据中的 7位 和 8位 变成10
3、一次性操作两位 对 这个32位数据中的 9位 和 10位 变成01
4、一次性操作两位 对 这个32位数据中的 11位 和 12位 变成00
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num_1 =55; //0000 0011 0111 -> 0001 1011 0111
num_1 |= (0x03 << 4); //11
num_1 |= (0x02 << 6); //10
num_1 |= (0x01 << 8); //01
num_1 |= (0x00 << 10); //00
printf("num_1 = %d\n" , num_1);
return 0;
}
练习2:
写一个小的登录程序,功能:
1、用户可以循环登录 例如输入错了一次密码 可以在进行输入
2、用户只能输错 3 次 3次后自动退出程序

#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char read_name[128];
char read_password[128];
char name[128] = "张三";
char password[128] = "111";
int count = 3;
while (count)
{
printf("请输入账号:\n");
scanf("%s", read_name);
printf("请输入密码:\n");
scanf("%s", read_password);
if ((!strcmp(read_name, name)) && (!strcmp(read_password, password)))
{
printf("恭喜登陆成功!\n");
break;
}
else
{
if(count==1){
printf("机会次数用尽,请您15分钟后再试\n");
--count;
}
else{
printf("登陆失败,你还有%d次机会\n",--count);
}
}
}
return 0;
}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)