随堂笔记 - Linux嵌入式ARM开发教程 -C语言

2023-10-13 07:20

本文主要是介绍随堂笔记 - Linux嵌入式ARM开发教程 -C语言,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

预处理

define

#define adc (2+3)
define :替换 注意加括号

关键字

数据类型

char

char :硬件处理的最小单位

硬件芯片操作的最小单位
bit 1/0
软件芯片操作的最小单位
1B = 8bit
4M速度? 4Mbit?4MB? Kbit/s KB/s

be :char buff[xx]; not be :int buff[xx];

int

int :编译器最优的处理能力,系统一个周期所能接受的最大处理单位
16bit 2B int
32bit 4B int
int a = 10;十进制10
int a = 010; 八进制8
int a = 0x10;十六进制16

long、short

long、short :特殊长度的限制符

unsigned、signed

unsigned、signed :内存空间的最高字节是符号位还是数据
unsigned 数据 signed 数字

float、double

float、double :内存存在形式
大小:
float 4B ,double 8B
浮点型常量 1.1 => double
1.0f =>float

void

void :语义符 声明 申请一种变量名,其类型靠强制类型转换
void a;

自定义数据类型

C编译器默认定义的内存分配不符合实际资源的形式

struct

元素之间的和,顺序有要求

union

共用起始地址的一段内容,技巧性代码

enum

被命名的整形常数的集合
enum abc{MOD = 100, TUE, WED} 依次累加
enum abc a = 800;
printf("the a is %lu:%d\n",sizeof(a),a);
the a is 4:800 a是一个整数,其值是在enum中取,勿这样用

typedef

typedef :对数据类型取别名
typedef int len_t len_t是int类型的外号,xxx_t 用typedef取的别名

逻辑结构

CPU顺序执行程序,用PC指针指向CPU执行位置

if else

int a = -1;
if(a) //真(非零即真)

switch、case、default

swtich(整形数字)

do、while、for

for:次数
while:条件

continue、break、goto

控制符
goto 函数内部跳转 同一个函数

类型修饰符

对内存资源存放位置的限定,资源属性中位置的限定

auto

默认情况 分配的内存可读可写的区域
区域如果在{ },则是栈空间

register

限制变量定义在寄存器上的修饰符,定义一些快速访问的变量,编译器会尽量的安排CPU的寄存器去存放这个变量,如果空间不足时,还是会放在存储器中。

注意:&取地址 对register不起作用

内存(存储器) 寄存器(快)
0x xxxxx R0,R2 …

static

应用场景:修饰三种数据:
1)、函数内部的变量
int fun{
int a; -->static int a;
}
2)、函数外部的变量
int a; -->static int a;
int fun{

}
3)、函数
int fun();–>static int fun();
printf(“the is %d\n”,fun);

const

常量的定义,只读的变量,但在RW中,可以用某种方法可写
const int a = 0x12345678;
int b = 0x11223344;
//a = 100; x
指针可以
int *p=&b;
p[1] = 100;
printf("the a is %s\n",a);
``
const char * const p;//第一个修饰*p 空间只读 指向字符串 【T】
char const *p const;//第二个修饰 p 地址只读 定义硬件资源

char *p = "xxxx"; // 默认const
*p = 'a'; // error!
char buf[] = {"xxx"}; // 可变

extern

外部声明

volatile

告知编译器编译方法的关键字,不优化编译
修饰变量的值的修改,不仅仅可以通过软件,也可以通过其他方式(硬件外部的用户)
int a = 100;
while(a == 100);
mylcd();

[a]: a的地址
f1:LDR R0, [a]
f2:CMP R0, #100
f3:JMPeq f1(优化前) --> JMPEQ f2(优化后)
f4:mylcd();

char *p;
volatile char *p; // 硬件访问用,防优化

杂项

sizeof

printf("the a is %d\n",sizeof(a));
printf("the a is %d\n",sizeof a);
printf("the a is %lu\n",sizeof(a));sizeof默认lu类型
sizeof : 编译器给我们查看内存空间容量的一个工具
sizeof 并不是函数名而是关键字

return

return : 返回的概念

运算符

算术操作运算

+、-、*、/、%

+:一个周期可以执行
*:多个周期,甚至软件模拟实现,第三方实现
%:0%3=0 1%3=1 2%3=2 3%3=0 n%m=res[0 - m-1] (取一个范围的数)(循环数据结构的下标)

逻辑运算

||、&&

先后顺序运算 满足条件直接退出
int a = 10;
int res;
res = ((a == 10) || (printf("!"));

>、<=、<、<=

int a = 0x0;
!a if(!a){}
~a 0xffff

? :

位运算

<<、>>

一个周期
取反加一 -1 ->11111111
-2 ->11111110
左移 正数负数一样
右移 符号变量有关 回不到0

int a = xxx;
while(a){
a = a>>1;
}
printf("!!!\n");

&、|

&:0 屏蔽 1 取出 清零器
| : 0 保留 1 设置 设置器

^、~

int a = 20;
int b = 30;
a = a^b;
b = a^b;
a = a^b;

~0xf0 = 0xffff ff0f

赋值运算

=

+=、-=…

内存访问符号

()

限制符
函数访问

【】

数组
内存访问的ID符号

{}

函数体的符号

->、.

&、*

指针

以p开头 int* p_xxx;
printf(“the p is %lu\n”,p_xxx);16进制用%x;

1.指针地址 多大?2.读取方式?
char *p2 = (char *)&b;
在32bit系统中,指针就是4个字节。
2^10 1K
2^20 1M
2^30 1G

float a = 1.2;
int *p;//char // unsigned char
p=&a;
printf("the p is %x\n",*p); // int 3f99 999a // char ffff fff9a // unsigned char 9a

1.0x0:地址的无效值,结束标志
if(p == 0x0) // NULL
2.指针同类型的比较才有意义

char **p;
hello world!!!
输出hello world!!!

005.c
int main(int argc, char **argv){
int i;
for(i = 0; i < argc; i++){
printf("the argv[%d] is %s\n", i, argv[i]);
}
return 0;
}
Linux
gcc -o build 005.c
./build hello 123 456
the argv[0] is ./build
the argv[1] is hello
the argv[2] is 123
the argv[3] is 456

while(argv[i] != NULL){
printf("the argv is %s\n,argv[i]");
i++;
}

数组

数据大小 读取方式
xxx[m] m的作用域是在申请的时候 建议符 可越界 xxx是常量
初始化:int a[10] = {10,20,30};CPU一般不支持空间和空间的拷贝,编译器初始化处理。
数组空间的初始化和变量的初始化本质不同,尤其在嵌入式的裸机开发中,空间的初始化往往需要库函数的辅助

char buff[10] = {'a','b','c'};
char buff[10] = {"abc"}; // ""带'\0’   4个字节
char buff[10] = "abc";  // 有两个abc 一个常量一个变量  常量向变量拷贝  buff[2] = 'e' 可以
char *p = "abc";    // 仅一个  p指向abc p[2] = 'e' 不可以
buf = "hello world" ; // 错误 第二次初始化不能直接赋值,只能逐一处理

一块空间当成字符空间,提供了一套字符拷贝函数 strcpy strncpy
原则:内存空间和内存空间的逐一赋值的功能的一个封装体,一旦空间中出现了0这个特殊值,函数就即将结束。
strcpy(buf,“hello world”);
strcpy 会内存泄漏 超过10个字符的拷贝

字符空间
ASCII码编码来解码的空间 ‘\0’结束 %s
char buff[10]; -> string
非字符串空间
数据采集 0x00-0xff 开辟一个数据盒子存储
unsigned char buff[10]; -> data
strcpy拷贝不合理 函数根据’\0’结束
用memcpy来内存拷贝
int buf[10];
int sensor_buff[100];
memcpy(buff, sensor_buff, 10*sizeof(int));
strncpy(buf,sensor_buff,10); // 00 00 00 23 会拷不进来

指针数组

指针数组:char a[100]; sizeof(a) = 1004;
多级指针:char **a;

多维数组

定义一个指针,指向int a[5][6] 的首地址

int *p; int *p[5]; int (*p)[5];
int a;                  int a[5];	
int a[5][6];
int (*p)[6] = a; int [5](*p) = a;

字节对齐、位域

位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,一个字节等于8位二进制数,在UTF-8编码中,一个英文字符等于一个字节。字节按照一定规则在空间上排列就是字节对齐。

 struct abc{char a;int b;}struct abc buff; // 1+4 = 5sizeof(buff) =8; ???8

效率,希望牺牲一点空间换取时间的效率
32bit 4个字节
最终结构体的倍数一定是4的倍数,定义顺序不一样,大小也不同,如果两个定义4个字节可以放下就合并,如 char short 4个字节

内存

1.大小。2.在哪里。
编译===》 汇编 ===》链接
*.0 build

int main(){int a;a = 0x10;printf("the a is %p\n",&a);   //  比16进制%x 多个0xprintf("the a is %p\n",main);return 0;
}

放在不同地方叫放在不同段
main 全局变量内存放的位置很低 a 局部变量很高


内核空间 应用程序不许访问


3G


栈空间 局部变量


运行时堆地址 malloc


全局的数据空间 (初始化的,未初始化的) static RW date bss
只读数据段 “hello world”(字符串常量) R TEXT
代码段 code(只读) R TEXT


0x8048xxxx


0x0:


栈空间

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

堆空间

运行时,可以自由,自我管理的分配和释放的空间,生存周期是由程序员来决定,分配释放必须配对。
分配:
malloc(),一旦成功返回分配好的地址给我们,只需要接受。对于读法由程序员灵活把握。输入参数指定分配的大小,单位是B。不随函数执行完释放!否则会内存泄漏。如:
void fun(){
char *p;
p = (char *)malloc(100);//未释放
return;
}
释放:
free§;

只读空间

程序+字符串+全局变量
静态空间,整个程序结束时释放内存,生存周期最长
main 只读空间
unsigned char *p;
p = (unsigned char *)main; // 告诉编译器仅赋值,
只读不可写,注意报段错误 Segmentation fault

size build//Linux 查看内存大小

TEXT(只读) data(已初始化) bss(未初始化) dec hex filename
977          264                         8                 1249 4el build

strings build // 只读数据段,字符串,“xxx”
加static 就会放到全局空间
nm bulid // 查看静态空间的段名
0804xxxx d a.1702 fun函数的static int a;
0804xxxx b a.1708 main函数的static int a;
0804xxxx T fun
0804xxxx T main

函数

用指针保存函数

int (*p)(int,int,char);  函数名即地址
int (*myshow)(const char *,...);
myshow = printf; // myshow = (char (*)(const char *,...))0x8048320; 
myshow("====\n");int (*p[7])(int,int};
p[0] = fun1;
......
p[day](10,20);switch(day){case 1:fun1(10,20);break;......
}

承上启下,返回回调;
调用者:
函数名(要传递的数据) // 实参
被调者:
函数的具体实现
函数的返回值 函数名(接受的数据){ // 形参
xxx;
}
实参传递给形参。传递的形式:拷贝。
值传递会拷贝,不会影响调用者。
地址传递。

空间的读写:只读空间加const 如:void fun(const char *p){}

int sprintf(char *str, const char *format, ...);   sprintf(buf,"%d",a);

空间的结束标志:分成字符空间和非字符空间
字符空间:0x00结束

void strlen(const char *p)
{int i = 0;if(p == NULL){//return ...}while(p[i]){//+++++++++++i++;}
}void strcpy(char *dest, const char *src);

非字符空间: 0x00不做结束标志,要有结束标志(数量)
unsigned char *p

void fun(unsigned char *p, int len){int i;for(i = 0; i < len; i++){//++++++}
}

void *:数据空间的标识符,可以是任意类型(非字符空间)

void *memcpy(void *dest, const void *src, size_t n);

printf("%s",buf);//00 00 12 54 // 00 会结束

int fun(void *buf,int len)
{
unsigned char *tmp = (unsigned char *)buf;
}
返回值:指针作为空间返回的唯一数据类型

 int *fun1(void);int main(){int *p;p = fun1();//fun2(p);//不变 fun3(&p); 可以
}

注意函数返回后内存回收,地址:指向的合法性,作为函数的设计者,必须保证函数返回的地址所指向的空间是合法的(不是局部变量)

char *fun(void){return "hello";   // char buf[] = "hello"; return buf; // 无效
}
int main (){char *p;p = fun();printf("the p is %s\n",p);return 0;
}

局部变量加static变静态区可以返回。只读区可以返回。堆区可以(malloc free)。

推荐:嵌入式程序员应知道的0x10个基本问题

#define ABC 123
#define ABC (100+23)UL // 如果值很大,可能越界,加L,无负值加UL
都是常量,编译器编译后都是123,都一样,程序调用时没有运算
2.
int a[10];
int *a[10];
int (*a)[10];
int fun(int);
int (*a)(int);
int (*a[10])(int);//一个有10个指针的数组,该指针指向一个函数
// 先右在左,右边是(则是函数名 ,所以(*a),要加括号
3.
在这里插入图片描述在这里插入图片描述
4.
在这里插入图片描述
5.
老师,再见。

这篇关于随堂笔记 - Linux嵌入式ARM开发教程 -C语言的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/201655

相关文章

DeepSeek模型本地部署的详细教程

《DeepSeek模型本地部署的详细教程》DeepSeek作为一款开源且性能强大的大语言模型,提供了灵活的本地部署方案,让用户能够在本地环境中高效运行模型,同时保护数据隐私,在本地成功部署DeepSe... 目录一、环境准备(一)硬件需求(二)软件依赖二、安装Ollama三、下载并部署DeepSeek模型选

mysqld_multi在Linux服务器上运行多个MySQL实例

《mysqld_multi在Linux服务器上运行多个MySQL实例》在Linux系统上使用mysqld_multi来启动和管理多个MySQL实例是一种常见的做法,这种方式允许你在同一台机器上运行多个... 目录1. 安装mysql2. 配置文件示例配置文件3. 创建数据目录4. 启动和管理实例启动所有实例

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Linux内存泄露的原因排查和解决方案(内存管理方法)

《Linux内存泄露的原因排查和解决方案(内存管理方法)》文章主要介绍了运维团队在Linux处理LB服务内存暴涨、内存报警问题的过程,从发现问题、排查原因到制定解决方案,并从中学习了Linux内存管理... 目录一、问题二、排查过程三、解决方案四、内存管理方法1)linux内存寻址2)Linux分页机制3)

使用DeepSeek API 结合VSCode提升开发效率

《使用DeepSeekAPI结合VSCode提升开发效率》:本文主要介绍DeepSeekAPI与VisualStudioCode(VSCode)结合使用,以提升软件开发效率,具有一定的参考价值... 目录引言准备工作安装必要的 VSCode 扩展配置 DeepSeek API1. 创建 API 请求文件2.

电脑没有仿宋GB2312字体怎么办? 仿宋GB2312字体下载安装及调出来的教程

《电脑没有仿宋GB2312字体怎么办?仿宋GB2312字体下载安装及调出来的教程》仿宋字体gb2312作为一种经典且常用的字体,广泛应用于各种场合,如何在计算机中调出仿宋字体gb2312?本文将为您... 仿宋_GB2312是公文标准字体之一,仿China编程宋是字体名称,GB2312是字php符编码标准名称(简

VScode连接远程Linux服务器环境配置图文教程

《VScode连接远程Linux服务器环境配置图文教程》:本文主要介绍如何安装和配置VSCode,包括安装步骤、环境配置(如汉化包、远程SSH连接)、语言包安装(如C/C++插件)等,文中给出了详... 目录一、安装vscode二、环境配置1.中文汉化包2.安装remote-ssh,用于远程连接2.1安装2

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

vscode保存代码时自动eslint格式化图文教程

《vscode保存代码时自动eslint格式化图文教程》:本文主要介绍vscode保存代码时自动eslint格式化的相关资料,包括打开设置文件并复制特定内容,文中通过代码介绍的非常详细,需要的朋友... 目录1、点击设置2、选择远程--->点击右上角打开设置3、会弹出settings.json文件,将以下内

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端