笔记 嵌入式C语言

    科技2022-08-06  119

    ***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 访问固定内存位置

    Processed: 0.010, SQL: 8