随堂笔记 - 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

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor