当前课程知识点:Embedded Software Design > Chapter 3 ARM C Program Optimization > 3.2 Data Type Selection for Variable > 3.2 Data Type Selection for Variables
返回《Embedded Software Design》慕课在线视频课程列表
返回《Embedded Software Design》慕课在线视频列表
各位同学大家好
我们来学习变量的数据类型选择
假设我们现在采用的是
32位的ARM处理器
Load Store不同数据类型的时候
它的效率是不同的
我们通过一个例子来进行说明
这个例子是求校验和
也就是现在有一段内存空间
我们要把
其中每一个单元的数全加起来
然后拿到这个和
由这个和来判断
这段空间的数值存储有没有错误
我们来看一下这段代码
它有一个整型指针的参数
叫做data
然后定义了一个字符型变量i
用这个i作为将来的循环变量
sun是最终要返回的校验和
通过一个64次的循环
把每一个单元的值都加到sum上
这就是当前这个函数的基本功能
然后我们要做一些讨论
把i声明为字符类型的优缺点
字符类型的表示范围超过了64
因为它可以达到255
所以对于这个程序来说完全够用
如果我们采用了字符类型
由于它只有八位
是否能够
更节省寄存器和内存空间呢
这是我们需要考虑的问题
怎么办呢
我们把刚才的程序反汇编成汇编指令
然后看一下
它实际都做了哪些工作
这就是它对应的汇编代码
第一行是MOV r2, r0
r0就是C语言当中的
函数的第一个参数
也就是data指针
指向这段空间的起始地址
我们先把起始地址赋值给r2
因为r0将来另有他用
接下来看第二行
我们给r0赋值为0
就是r0我们将来要用来保存和
所以首先要给它清零
r1是什么呢
r1是计数器的值
也就是当前访问到了哪一个元素
然后我们给它逻辑左移两位
其目的是什么呢
因为ARM是一个32位处理器
每一个字是四个字节
我们给它逻辑左移两位
恰好相当于是给它乘4
然后把它和r2相加
r2就是起始地址了
这个加的和就是
每次我们要找的元素的起始地址
然后我们把地址处的内容拿给r3
在这个循环的第一轮中
r3是整个内存区域第一个单元的值
那么这是一个32位的数据
接下来我们给r1自加
也就是它加1
相当于循环变量自加
再接下来注意这条语句
我们要把r1和0xff做一个与操作
结果还是放到r1中
那么大家想这个有什么用
由于r1是用来保存循环变量
而我们把循环变量i
设计为了一个字符类型的值
那么它的值最多不能够超过255
所以在汇编程序中
就要对此做出保证
把它和0xff做一个与操作
就能够让它的值不会超过255
再下面把r1和0x40做比较
0x40的对应的十进制数就是64
这个是做一个循环终止条件的判断
然后再下面是一个加法
把r0和r3相加结果放到r0中
也就是把刚取出来的r3的值
加到和当中
和就保存在r0里面
然后再下面就要做跳转
根据刚才比较的结果
如果r1的值小于0x40
它就会跳到loop这个地方
进行下一轮循环
否则就往下走
往下走就是把r14的值送给pc
r14就是链接寄存器
它保存的是程序的返回地址
所以把它的值赋值给pc
那么这个函数就会返回
这个就是校验和对应的汇编代码
那么在其中我们要重点讨论的就是
刚才红色的那条指令
i是一个字符型的变量
超过255就必须给它归零
所以汇编程序中要确保不超过255
刚才那个程序一共是十条汇编指令
我们可以对这个程序做一点修改
比如说我们把这个循环变量i
用一个无符号整型变量来代替
我们看一下效果会怎么样
它的汇编指令一共是九条指令
比刚才少了一条
少了哪一条呢
恰好就是对i做约束的那条指令
也就是把r1的值和0xFF相与
那么这条指令就没有了
因为现在循环变量是一个整型变量
我们不需要保证它总是小于255
所以那条与操作的指令就没有了
这样的话程序就少了一条指令
所以它的效率会有一定程度的提高
我们再来看一个例子
这个是16位数据的校验和的例子
我们看这个函数
它的返回值是一个短整型数据
也就是16位的数据
然后它的参数是一个短整型的指针
它的校验和
也是一个短整型的数据类型
在这个汇编代码当中
首先仍然是做初始地址赋值给r2
然后r0用来保存和
r1仍然是循环计数器
但是现在有这样两条红色的指令
一条是把r1逻辑左移一位
然后和r2相加结果送给r3
这个指的是
因为现在是16位数据相加
所以r1每一个值要逻辑左移一位
也就是让它乘以二
那么对应的来说
八位的数据乘以二就是16位的数据
然后和r2这个初始地址
相加结果送给r3
所以在每一圈循环中
r3保存的就是要取的那个数据的地址
然后用这条LDRH指令
把r3这个地址处的
一个16位数据取出来
送给r3这个寄存器
然后接下来是循环变量的增加
以及循环条件的判断
然后这条加法指令
就是要把取出来的r3的值
和保存和的r0的值相加
结果送到r0
再下面我们发现又有两条红色指令
一条是把r0逻辑左移16位
接下来要把r0算术右移16位
为什么要移来移去
因为r0保存的是sum
也就这个和
而我们把这个和定义成了短整型
也就是16位的长度
所以我们在运算过程中
必须随时保证它的长度就是16位
我们给它逻辑左移再算术右移
其实就是把它的高16位去掉了
通过这种方式
保证这个和永远是短整型
然后接下来
就做一个循环终止条件的判断
如果循环没有结束那就往上跳
如果结束了就往下跳
程序就结束了
通过这个例子
我们看到它一共有12条语句
比刚才的九条多了三条
尤其重要的是
在这个循环内部我们发现
反复做移位
实际上循环执行的过程中
每一圈都要增加几条指令
所以它的总的时间会增加很多
那么这种编程方式是不够好的
我们做一个讨论
由于LDRH指令和LDR指令不同
它不支持移位地址偏移
所以需要用一条指令单独计算地址
我们必须这样做
两次移位对应的是短整型数据类型
怎么样克服刚才程序的缺点呢
我们可以用data指针来操作数据
避免使用数组
因为我们可以看到
刚才是使用数组进行操作的
所以我们可以用指针来操作
然后可以运算过程中
都用整型来计算
计算完之后再返回短整型的数据
也就是我们把程序做这样的修改
我们发现校验和定义成了整型
然后在这个循环运算过程中
用的都是整型
只不过返回的时候
我们把返回值
做了一个到短整型的强制类型转换
然后返回
针对这样的代码
我们看一下它对应的汇编语句
首先从内存中取数的这个指令
用一条红色的语句就能够完成了
其次循环的起始位置在这loop
然后循环的截止位置
在BCC这条语句
我们发现
把数据类型从整型
转换成短整型的两条语句
挪到了循环的外面
所以这样总体上来说
程序不但更加短小
而且由于关键语句移到循环的外面
整体上它的执行的时间会少很多
从而获得了程序效率的提升
我们总结一下
通过采用整型类型
省去了多余的移位操作
移位移动到循环外
同时尽量使用整型数据
那什么时候用字符型和短整型呢
如果你要用它的溢出归零的特性
那你就用
否则你尽量就用整型数据
这部分内容我们就介绍到这
谢谢大家
-1.1 The Overview of Embedded System
--1.1 The Overview of Embedded System
--1.1 The Overview of Embedded System
-1.2 The Overview of Embedded Software Design
--1.2 The Overview of Embedded Software Design
--1.2 The Overview of Embedded Software Design
-Chapter 1 test Overview
-2.1 Software Architecture
-2.2 The Object Orientation of C
--2.2 The Object Orientation of C
--2.2 The Object Orientation of C
-2.3 Chinese Character Processing
--2.3 Chinese Character Processing
--2.3 Chinese Character Processing
-2.4 Screen Operation
-2.5 Input Event
-Chapter 2 test Overview of Embedded C Programming
-3.1 The Thought of Code Optimization
--3.1 The Thought of Code Optimization
--3.1 The Thought of Code Optimization
-3.2 Data Type Selection for Variable
--3.2 Data Type Selection for Variables
--3.2 Data Type Selection for Variable
-3.3 Optimizing a Loop Executed in a Fixed Number of Times
--3.3 Optimizing a Loop Executed in a Fixed Number of Times
--3.3 Optimizing a Loop Executed in a Fixed Number of Times
-3.4 Optimizing a Loop Executed in an Unfixed Number of Times
--3.4 Optimizing a Loop Executed in an Unfixed Number of Times
--3.4 Optimizing a Loop Executed in an Unfixed Number of Times
-3.5 Loop Unrolling
-3.6 Pointer Aliasing
-3.7 Struct
-Chapter 3 ARM C Program Optimization
-4.1 The Introduction to Linux
--4.1 The Introduction to Linux
--4.1 The Introduction to Linux
-4.2 The shell of Linux
-4.3 The Basic Operations of Linux
--4.3 The Basic Operations of Linux
--4.3 The Basic Operations of Linux
-4.4 The Network Commands of Linux
--4.4 The Network Commands of Linux
--4.4 The Network Commands of Linux
-Chapter4 The Linux Operating System
-5.1 The Overview of the Toolchain
--5.1 The Overview of the Toolchain
--5.1 The Overview of the Toolchain
-5.2 Editor vi
-5.3 The Overview of gcc
-5.4 The Usage of gcc
-5.5 The Introduction to gdb
-Section 5-1 test Linux C Programming Toolchain
-5.6 The Working Principle of Makefile
--5.6 The Working Principle of Makefile
--5.6 The Working Principle of Makefile
-5.7 Makefile Instance Analysis
--5.7 Makefile Instance Analysis
--5.7 Makefile Instance Analysis
-5.8 Makefile Design
-5.9 A Comprehensive Instance of Makefile
--5.9 A Comprehensive Instance of Makefile
--5.9 A Comprehensive Instance of Makefile
-Chapter 5-2 test Makefile
-6.1 Linux-based Embedded Platform
--6.1 Linux-based Embedded Platform
--6.1 Linux-based Embedded Platform
-6.2 BootLoader
-6.3 Application Design Process
--6.3 Application Design Process
--6.3 Application Design Process
-Chapter 6 test Construction of Embedded Software
-7.1 The Attributes of Files
-7.2 File Operation
-7.3 Examples of File Operation
--7.3 Examples of File Operation
--7.3 Examples of File Operation
-7.4 The Operations on Directories
--7.4 The Operations on Directories
--7.4 The Operations on Directories
-7.5 Obtaining a Directory List
--7.5 Obtaining a Directory List
--7.5 Obtaining a Directory List
-7.6 Memory Mapping
-7.7 An Example of Memory Mapping
--7.7 An Example of Memory Mapping
--7.7 An Example of Memory Mapping
-Chapter 7 test File Directory and Memory
-8.1 Process Creation
-8.2 The Way to Start a Program in a Process
--8.2 The Way to Start a Program in a Process
--8.2 The Way to Start a Program in a Process
-8.3 Waiting for a Process to End
--8.3 Waiting for a Process to End
--8.3 Waiting for a Process to End
-8.4 The Introduction to Threads
--8.4 The Introduction to Threads
--8.4 The Introduction to Threads
-8.5 An Example of Multithreading Programming
--8.5 An Example of Multithreading Programming
--8.5 An Example of Multithreading Programming
-8.6 Thread Synchronization
-8.7 The Attribute of a Thread
--8.7 The Attribute of a Thread
--8.7 The Attribute of a Thread
-Chapter 8 test Processes and Threads
-9.1 The Introduction of Signals
--9.1 The Introduction of Signals
--9.1 The Introduction of Signals
-9.2 Sending and Capturing Signals
--9.2 Sending and Capturing Signals
--9.2 Sending and Capturing Signals
-9.3 A More Robust Signal Programming Interface
--9.3 A More Robust Signal Programming Interface
--9.3 A More Robust Signal Programming Interface
-9.4 Signal Set Processing
-Chapter 9 test Signals
-10.1 Unnamed Pipe
-10.2 Named Pipe
-10.3 Semaphore Introduction
-10.4 An Example of Semaphores
--10.4 An Example of Semaphores
--10.4 An Example of Semaphores
-10.5 The Introduction to Shared Memory
--10.5 The Introduction to Shared Memory
--10.5 The Introduction to Shared Memory
-10.6 An Example of Shared Memory
--10.6 An Example of Shared Memory
--10.6 An Example of Shared Memory
-10.7 The Introduction to Message Queues
--10.7 The Introduction to Message Queues
--10.7 The Introduction to Message Queues
-10.8 An Example of Message Queue
--10.8 An Example of Message Queue
--10.8 An Example of Message Queue
-Chapter 10 test Interprocess communication
-11.1 Socket Introduction
-11.2 A Socket Programming Example
--11.2 A Socket Programming Example
--11.2 A Socket Programming Example
-11.3 The Interface Functions of Sockets
--11.3 The Interface Functions of Sockets
--11.3 The Interface Functions of Sockets
-11.4 Network Socket
-11.5 Access the System Service
--11.5 Access the System Service
--11.5 Access the System Service
-11.6 Multi-Client Programming
--11.6 Multi-Client Programming
--11.6 Multi-Client Programming
-Chapter 11 test Sockets
-12.1 The Introduction to Kernel Modules
--12.1 The Introduction to Kernel Modules
--12.1 The Introduction to Kernel Modules
-12.2 The Design of Kernel Modules
--12.2 The Design of Kernel Modules
--12.2 The Design of Kernel Modules
-12.3 The Introduction to Linux Device Drivers
--12.3 The Introduction to Linux Device Drivers
--12.3 The Introduction to Linux Device Drivers
-12.4 The Important Data Structures of Drivers
--12.4 The Important Data Structures of Drivers
--12.4 The Important Data Structures of Drivers
-12.5 An Instance of a Virtual Character Device Driver
--12.5 An Instance of a Virtual Character Device Driver
--12.5 An Instance of a Virtual Character Device Driver
-Chapter 12-1 test Module and Driver
-12.7 Interrupt Key Driver Program
-Chapter 12-2 test The Example of Driver
-Final exam