版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、.,第5章 嵌入式C语言程序设计基础,5.1 嵌入式C语言的预处理伪指令 5.2 嵌入式C语言的基本数据类型 5.3 程序的控制结构 5.4 函 数 5.5 数组 5.6 指 针 5.7 构造数据类型 5.8 汇编语言与C/C+的混合编程 5.9 嵌入式Linux下C语言编程文件的操作,.,5.1 嵌入式C语言的预处理伪指令,1文件包含伪指令 文件包含伪指令可将头文件包含到程序中,头文件中定义的内容符号常量,复合变量原型、用户定义的变量原型和函数的原型说明等。编译器编译预处理时用文件包含的正文件内容替换到实际程序中。 (1)文件包含伪指令的格式 # include ;标准头文件 # inclu
2、de “头文件名.h” ;自定义头文件 # include 宏标识符,.,5.1 嵌入式C语言的预处理伪指令,(2)包含文件伪指令的说明 常在头文件名后用.h作为扩展名,可带或不带路经。 头文件可分为标准头文件和自定义头文件。 尖括号内的头文件为标准头文件,由开发环境或系统提供。 双引号内的头文件为用户自定义头文件。搜索时,首先在当前目录中搜索,其次按环境变量include指定的目录顺序搜索。 搜索到头文件后,就将该伪指令直接用头文件内容替换。,.,5.1 嵌入式C语言的预处理伪指令,例5.1 标准头文件定义 # include # include string.h和stdio.h是标准头文件
3、,按环境变量 include指定的目录顺序搜索string.h和stdio.h。 例5.2 用户自定义头文件定义 # include “s3c2410-adc.h” s3c2410-adc.h头文件是用户自定义有关三星s3c2410的ARM处理器的A/D转换器各寄存器。,.,5.1 嵌入式C语言的预处理伪指令,2宏定义伪指令 宏定义伪指令分为:简单宏、参数宏、条件宏、预定义宏及宏释放。 (1)简单宏 格式如下: # define 宏标识符 宏体 宏体是由单词序列组成。宏体超长时,允许使用续行符“”进行续行,续行符和其后的换行符 n 都不会进入宏体。 在定义宏时,应尽量避免使用C语言的关键字和预
4、处理器的预定义宏,以免引起灾难性的后果。 在源文件中,用预处理器伪指令定义过宏标识符之后,就可用宏标识编写程序。当源文件被预处理器处理时,每遇到该宏标识符,预处理器便将宏展为宏体。,.,5.1 嵌入式C语言的预处理伪指令,(2)参数宏 格式如下: # define 宏标识符(形式参数表) 宏体 形式参数表为逗号分割的形式参数。 宏体是由单词序列组成。宏体超长时,允许使用续行符“”进行续行,续行符和其后的换行符 n 都不会进入宏体。 使用参数宏时,形式参数表应换为同样个数的实参数表,这一点类似于函数的调用。参数宏与函数的区别在于参数宏的形参数表中没有类型说明符。 预处理器在处理参数宏时使用2遍宏
5、展开。第1遍展开宏体,第2遍对展开后的宏体用实参数替换形式参数。,.,例5.3 在Linux系统的/include/asm-arm/arch-s3c2410/S3C2410.h头文件中定义了各Nand Flash控制寄存器,其源代码如下: #define bNAND_CTL(Nb) _REG(0 x4e000000 + (Nb) #define NFCONF bNAND_CTL(0 x00) #define NFCMD bNAND_CTL(0 x04) #define NFADDR bNAND_CTL(0 x08) #define NFDATA bNAND_CTL(0 x0c) #define
6、 NFSTAT bNAND_CTL(0 x10) #define NFECC bNAND_CTL(0 x14),5.1 嵌入式C语言的预处理伪指令,.,5.1 嵌入式C语言的预处理伪指令,例5.4 在Linux下ARM S3C2410X芯片的A/D转换的驱动程序的头文件s3c2410-adc.h中定义了下面三个宏。 #define ADC_WRITE(ch, prescale) (ch)16) /*定义ADC设备的主设备号*/ typedef struct struct semaphore lock; /*内核信号量,当多个用户程序同时访问一个ADC控制器时,用lock 进行同步*/ wait
7、_queue_head_t wait; /*等待队列*/ int channel; /*ADC通道号*/ int prescale; /*预定标值*/ ADC_DEV;,5.1 嵌入式C语言的预处理伪指令,.,static ADC_DEV adcdev; #define START_ADC_AIN(ch, prescale) do ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT(ch) ; ADCCON |= ADC_START; while(0)/*设置S3C2410X的ADC的通道为ch、预定标值为prescale*/ / PRESC
8、ALE_EN宏对应ARM S3C2410X芯片的A/D转换控制寄存器的第14位 PRSCEMN,即A/D转换器预标器使能; / PRSCVL宏对应ARM S3C2410X芯片的A/D转换控制寄存器的第6位,设置预定标值; / ADC_INPUT 宏对应ARM S3C2410X芯片的A/D转换控制寄存器的第3 5位,选择通道号; /ADCCON |= ADC_START; ADCCON 0 为置1,准备采集数据,5.1 嵌入式C语言的预处理伪指令,.,5.1 嵌入式C语言的预处理伪指令,(3)条件宏定义 格式如下: 格式1: # ifdef 宏标识符 # undef 宏标识符 # define
9、宏标识符 宏体 # else # define 宏标识符 宏体 # endif,.,格式2: # ifndef 宏标识符 # define 宏标识符 宏体 # else # undef 宏标识符 # define 宏标识符 宏体 # endif 其中: 格式1是测试存在,格式2是测试不存在。 else可有,也可没有。,5.1 嵌入式C语言的预处理伪指令,.,5.1 嵌入式C语言的预处理伪指令,(4)宏释放 用于释放原先定义的宏标识符。经释放后的宏标识符可再次用于定义其他宏体。 格式如下: # undef 宏标识符 例5.6 #define SIZE 512 buf=SIZE*blks /*宏扩
10、展为buf=512*blks; */ undef SIZE #define SIZE 128 buf=SIZE*blks /*宏扩展为buf=128*blks; */,.,5.1 嵌入式C语言的预处理伪指令,3条件编译伪指令 格式如下: # if(条件表达式1) # elif (条件表达式2) # elif (条件表达式3) # elif (条件表达式n) # else # endif,.,5.1 嵌入式C语言的预处理伪指令,例5.7 # if _B0SIZE=B0SIZE_BYTE typedef unsigned char PB0SIZE; # elif _B0SIZE=B0SIZE_SH
11、ORT typedef unsigned short PB0SIZE; # elif _B0SIZE=B0SIZE_WORD typedef unsigned long PB0SIZE; # endif,.,5.2嵌入式C语言的基本数据类型,5.2.1 数据类型与表达式,.,5.2 嵌入式C语言的基本数据类型,(1) 类型修饰符,.,5.2 嵌入式C语言的基本数据类型,(2) 访问修饰符 C语言有两个用于控制访问和修改变量方式的修饰符,分别是常量(const)和易变量(volatile)。带const修饰符定义出的常量在程序运行过程中始终保持不变。 例如: const int num; 例如:
12、 const int num=100; volatile修饰符用于提醒编译程序,该变量的值可以不通过程序中明确定义的方法来改变。 const和volatile可以同时使用。 例如,假设0 x30是一个只随外部条件而变化的口地址值,那么就恰好需要用下述说明来避免偶然因素所产生的副作用的影响。 const volatile unsigned char *port=0 x30;,.,5.2 嵌入式C语言的基本数据类型,2. 构造数据类型 数组是一组连续、有序的存放在一起的具有相同类型的数据。 结构体是将不同类型的数据按一定顺序存放在一起的数据结构。 共用体是将不同类型的数据都存放在同一起始地址的内存
13、单元中,共用一段内存以节省内存单元。 枚举是只有几种可能的值,将其一一列举出来。实际是用符号来表示若干个可取的整型值,它是整型的一个子集。,.,5.2 嵌入式C语言的基本数据类型,3. 指针类型 指针可以有效地表示复杂的数据结构;能动态分配内存;能方便地使用字符串;有效而方便地使用数组;在调用函数时能得到多于一个的值;能直接处理内存地址等。 指针类型迥异于前述各种数据类型,不管是简单类型的数据,还是构造类型数据,均是代表数据的,而指针类型是代表地址的。,.,5.2 嵌入式C语言的基本数据类型,5.2.2 常量 1. 数值常量 (1) 整型常量 整型常量也称为整型常数或整数。 C整型常量按进制分
14、可分为十进制整数,八进制整数和十六进制整数。 (2) 实型常量 实型常量有单精度实型常量和双精度实型常量。可用小数形式或指数形式表示。 (3) 字符常量,.,5.2 嵌入式C语言的基本数据类型,.,5.2 嵌入式C语言的基本数据类型,2. 字符串常量 字符串常量简称字符串,是用一对双引号括起来的字符序列。 例如“China”就是一个字符串常量。 若数字被定义为字符型之后就不能参与数值运算,如5和5是不同的。5是字符常量,不能直接参与运算,而只能以其ASCII码值(0 x35)来参与运算。,.,5.2 嵌入式C语言的基本数据类型,3. 符号常量 (1)不带参数的宏定义 宏定义命令define的一
15、般形式是: define 宏名 字符串 用来终止宏名作用域命令undef的一般形式是: undef 宏名 例5.8: define PI 3.14159/*定义PI为常量,其值是3.14159 */ main( ) undef PI /*终止宏名PI的作用域*/ f1( ),.,5.2 嵌入式C语言的基本数据类型,(2)带参数的宏定义 它不是进行简单的字符串替换,还要进行参数替换。 其定义的一般形式为: define 宏名(参数表) 字符串 其中字符串中包括参数表中所指定的参数。在使用时,要将程序中宏名后的实际参数代入字符串中参数的位置。例如: define S(a, b) a*b area=
16、S(3, 2); 经编译预处理, 该语句被展开成 area=3*2;,.,5.2 嵌入式C语言的基本数据类型,说明: (1) 宏名和参数表左括号之间不能有空格, 否则按不带参宏替换了。 (2) 字符串中应注意括号的使用,以保证运算次序。如上例改成 area=S(1+2, 2); 经展开后变成 area=1+2*2; 这就不合要求了。 此时, 可改写成 define S(a, b) (a)*(b) area=S(1+2, 2) 经展开后变成 area=(1+2)*(2); 就不会出现错误了。,.,5.2 嵌入式C语言的基本数据类型,5.2.3 变量 1. 变量的定义 变量定义的一般形式如下: 存
17、储类型 类型说明符 修饰符 标识符 =初值,标识符=初值 ; 变量的定义由5部分组成,方括号中的可有可无,变量定义的具体情况而定。,.,5.2 嵌入式C语言的基本数据类型,(1)类型说明符 对于数字与字符,其常用的类型主要有8种:char、unsigned char、int、unsigned、long、unsigned long、float、double。 void 类型(抽象型),在具体化时可用类型强制来指定类型说明符中的任意一类。 通过typedef定义的类型别名。为了增加程序的可读性和移植程序时的方便,C语言允许用户为C语言固有的类型用typedef起别名。 格式如下: typedef
18、C固有的简单类型或复合类型别名标识符 ; 用别名代替原来的类型,在说明中用作类型说明符。别名一般用大写字符,例如: typedef long BIG BIG x=80000;,.,5.2 嵌入式C语言的基本数据类型,(2) 标识符 变量名可以是C语言中允许的合法标识符。 每一个变量都必须进行类型说明,也就是变量要先定义,后使用。 当一个变量被指定为某一确定类型时,将为它分配若干相应字节的内存空间。如在32位体系的ARM系统中,char型为1字节,int型为4字节,float为4字节,double为8字节。当然,不同的体系结构的系统可能稍有差异。 变量可以在程序内的三个地方定义: 在函数内部,
19、在函数的参数(形参)定义中或在所有的函数外部。由此定义的变量分别称为局部变量, 形式参数和全局变量。在不同地方定义的变量,其作用域范围不同。在同一层次定义的变量不能与数组、指针、函数和其它变量同名。 变量是用来存放数据的,由于数据有不同的类型,因此要定义相应类型的变量去存放它。这些数据称为相应变量的值。,.,5.2 嵌入式C语言的基本数据类型,(3) 存储类型 存储类型指定被说明对象所在内存区域的属性。 存储空间分为代码区与数据区两个部分。变量存储在数据区,数据区又可分为静态存储区与动态存储区。 静态存储是指在程序运行期间给变量分配固定存储空间的方式。如全局变量存放在静态存储区中,程序运行时分
20、配空间, 程序运行完释放。 动态存储是指在程序运行时根据实际需要动态分配存储空间的方式。如形式参数存放在动态存储区中,在函数调用时分配空间,调用完成释放。 对于静态存储方式的变量可在编译时初始化,默认初值为0或空字符。对动态存储方式的变量如不赋初值,则它的值是一个不确定的值。 在C语言中,具体的存储类别有自动(auto)、寄存器(register)、静态(static)及外部(extern)四种。静态存储类别与外部存储类别变量存放在静态存储区,自动存储类别变量存放在动态存储区,寄存器存储类别直接送寄存器。,.,5.2 嵌入式C语言的基本数据类型, 局部变量的存储方式 局部变量一般用自动方式存储
21、,用保留字auto加以定义,此时称为自动变量,是动态存储,在函数的调用过程中存在,由编译系统自动处理。例如: void f( ) auto int i, j; auto float x, y; /*局部变量i,j,x,y以自动方式存储*/ C语言规定,自动变量可省去说明符auto。如果希望函数调用完后局部变量的值被保留,不释放其所占存储单元,这时必须将其存储方式定义为静态存储方式,用保留字static加以定义。,.,5.2 嵌入式C语言的基本数据类型, 全局变量的存储方式 全局变量一般用外部存储方式存储,用保留字extern加以定义。 变量的作用域是构成整个程序的所有程序文件,也就是定义的外部
22、变量可供其它程序文件使用。,.,5.2 嵌入式C语言的基本数据类型,例如5.9 程序由两个程序文件file1.c与file2.c组成。 /*file1.c*/ extern int a; /*定义extern存储方式变量a*/ main( ) int pow( ); int n; int p; scanf(%d, ,.,5.2 嵌入式C语言的基本数据类型,/*file2.c*/ extern int a; /*申明本文件中使用的是已定义的外部变量a*/ int pow(x) int x; int i, t=1; for(i=1; i=x; i+) t*=i; return(t); ,.,5.2
23、 嵌入式C语言的基本数据类型,(4)赋初值部分 若初值省略,则存储类型是自动(auto) 寄存器(register)的变量为随机值 存储类型是static的变量被编译器自动清0 对于指针,无论什么存储类型,一律置为空指针(Null)。 使用等号为变量赋初值,注意的是:指针必须用地址量作为初值,字符可用其编码值(例如ASCII码)或用单引号括起的字符作为初值。对于静态变量,只在定义说明时赋初值一次。,.,5.2 嵌入式C语言的基本数据类型,(5)修饰符 用于对变量进行特殊的修饰。修饰符包括以下3类: const常量修饰符,被修饰的变量或变量指针是常量。 volatile易失性修饰符,说明所定义的
24、变量或指针,是可以被多种原因修改的。如有的变量在中断服务程序中会被修改,有的会被I/0口修改,这种修改带有随机性,防止丢失任何一次这种修改,因此要把它修饰为易失性的变量,注意,禁止把它作为寄存器变量处理,也禁止对它进行任何形式的优化。 near、far近、远修饰符,用于说明访问内存中变量在位置上的远近。 特别注意: 格式中的方括号是可选项,可有可无。 一个说明语句可以同时说明多个同类型的变量,变量之间用逗号隔开,变量可以在说明时赋初值; 说明语句一定要有终止符“;”结束。,.,5.2 嵌入式C语言的基本数据类型,2. C语言中各种类型的变量 C语言中有以下几种类型的变量: 整型变量、实型变量、
25、字符型变量和构造类型变量等。 整型变量用来存放整型数值。整型变量可分为:基本型(int),短整型(short int或short),长整型(long int或long)和无符号型(unsigned int,unsigned short,unsigned long)。 实型变量分为单精度型(float)和双精度型(double)两类。 字符型(char)变量内存放字符型常量,在内存单元中仅占一个字节。其内存中存放的是该字符的ASCII码。 枚举型变量 枚举型是一个整型常量的集合。这些常量指定了所有该类型变量可能具有的各种合法值。枚举在我们日常生活中十分常见。例如,星期的枚举为:星期日, 星期一,
26、 星期二,星期三,星期四,星期五,星期六。 ,.,5.2 嵌入式C语言的基本数据类型,2. C语言中各种类型的变量 C语言中有以下几种类型的变量: 整型变量、实型变量、字符型变量和构造类型变量等。 整型变量用来存放整型数值。整型变量可分为:基本型(int),短整型(short int或short),长整型(long int或long)和无符号型(unsigned int,unsigned short,unsigned long)。 实型变量分为单精度型(float)和双精度型(double)两类。 字符型(char)变量内存放字符型常量,在内存单元中仅占一个字节。其内存中存放的是该字符的ASC
27、II码。 枚举型变量 枚举型是一个整型常量的集合。这些常量指定了所有该类型变量可能具有的各种合法值。枚举在我们日常生活中十分常见。例如,星期的枚举为:星期日, 星期一, 星期二,星期三,星期四,星期五,星期六。 ,.,5.2 嵌入式C语言的基本数据类型,5.2.4 运算符,.,5.2 嵌入式C语言的基本数据类型,5.2.4 运算符,说明: (1) +、-、*、%与数学中运算类似,先乘除后加减,也就是按优先级顺序进行运算,优先级小的先运算。 (2) 求余运算符(%)仅用于整型数据,不能用于实型和双精度实型。它的作用是取整数除法的余数。如1%2的结果是1;10%3的结果也是1。 (3) 赋值运算符
28、(=)是将右边表达式的值赋给左边的变量。赋值运算符左边必须是变量等有存贮单元的元素,而不能是常量或表达式。 (4) +、-仅用于整型变量,指针变量。用于整型变量在原值上加1或减1;用于指针变量是取下一地址或上一地址。 (5) +、-、*、/、%可以与赋值号=组成复合赋值运算符+=、-=、*=、/=、%=。,.,5.2 嵌入式C语言的基本数据类型,2. 关系运算符和逻辑运算符,.,5.2 嵌入式C语言的基本数据类型,2. 关系运算符和逻辑运算符,说明: (1) 当关系运算符两边的值满足关系时为真,返回1;如不满足关系时为假,返回0。 (2) 关系运算符、=、=、31); 运行输出结果为0。因为两
29、个是同一优先级,53的结果为1,而11的关系不满足,所以最后结果为0。 又如:printf(%dn,1=1135); 运行输出结果为1。因为的优先级比=高,则1135的结果为1,而1=1的关系满足,所以最后结果为1。 ,.,5.2 嵌入式C语言的基本数据类型,3. 位运算符,.,5.3 程序的控制结构,5.3 程序的控制结构 程序控制语句用于控制程序的流程,以实现程序的各种结构方式。包括: 条件判断语句:if ,switch 循环执行语句:do while,while,for 转向语句:break,goto,continue,return,.,5.3 程序的控制结构,5.3.1 选择结构 用i
30、f语句可以实现简单选择结构。其语法形式为 if(表达式)语句1 else 语句2 执行顺序是:首先计算表达式的值,若表达式值为true,则执行语句1;否则执行语句2。 if语句中的语句2可以为空,当语句2为空时,else可以省略,成为如下形式: if(表达式)语句1 其中,语句1和语句2不仅可以是一条语句,而且可以是大花括号括起来的多条语句,即复合语句。,.,5.3 程序的控制结构,5.3.2 switch语句 switch语句的语法形式如下: switch(表达式) case常量表达式1:语句1 case常量表达式2:语句2 case常量表达式n:语句n default:语句 n+1 ,.,
31、5.3 程序的控制结构,5.3.3 循环结构 嵌入式Lunux C语言中有三种循环控制语句,即while,do while,for循环语句。while和do while是两种不同的循环结构,即当型循环和直型循环,其格式如下: 1while语句(当型循环) while语句的语法形式为: while(表达式) 循环体语句 ,.,5.3 程序的控制结构,5.3.3 循环结构 2do-while语句(直型循环) 语法形式: do 循环体语句 while(表达式); 执行顺序是:当流程执行到do后,立即执行循环体语句,然后再判断循环条件表达式的值。当表达式为true时,继续执行循环体;否则结束循环,该语
32、句结构使循环至少执行一次。,.,5.3 程序的控制结构,3for语句 for语句的使用最为灵活,既可以用于循环次数确定的情况,也可以用于循环次数未知的情况。for语句的语法形式如下: for(表达式1;表达式2;表达式3) for语句的执行流程为: (1) 首先计算表达式1的值。 (2) 再计算表达式2,如果表达式2的值为false,则退出循环。 (3) 如果表达式2的值为true,则执行一次循环体,然后计算表达式3的值。 (4) 转回(2),表达式2的值决定是否继续执行循环体。,.,5.3 程序的控制结构,5.3.4 其他控制语句 1break语句 break 语句只用于switch语句或循
33、环体中,作用是使程序从switch语句内跳出或结束本次循环,转去执行后面的语句。由于break语句的转移方向是明确的,所以不需要语句标号与之配合。 2continue语句 continue语句仅用于循环体中,其作用是结束本次循环,接着开始判断循环条件,决定是否继续执行下一次循环。 3goto语句 goto语句的语法格式为 goto goto语句的作用是跳转到语句标号处执行程序。,.,5.4 函数,5.4 函 数 1函数定义 一个完整的函数定义由两部分组成,即函数头与函数体。函数定义的一般语法形式为: (形式参数表) 说明性语句序列; 实现函数功能的语句系列; 其中,类型标识符规定了函数的返回值
34、类型。函数的返回值是返回给主调函数的处理结果,由函数体部分的return语句带回。无返回值的函数其类型标识符为void,不必有return语句。形式参数表(简称形参表)的内容如下: 类型l 形参名1,类型2 形参名2,类型n 形参名n,.,5.4 函数,2调用函数 调用函数必须遵守先定义后调用的原则,否则,需要在调用函数之前在主调函数中声明函数原型。 函数原型声明形式: (1) (参数类型1,参数类型2); (2) (参数类型1 参数名1,参数类型2 参数名2); 函数的调用形式: (实参1,实参2,实参n),.,5.4 函数,例如在中出现的create_mapping函数定义(省略了括号内“
35、”的语句)。 static void _init create_mapping(struct map_desc *md) 定义这个函数的各项含义如下: (1)类型说明符static void _init,其中的static 说明符用于指明这个静态的函数只可被这一文件内的其他函数调用。 void 说明符指明该函数是无返值类型。而_init是宏定义的说明符。 (2)函数名为create_mapping。 (3)这个函数只有一个形式参数md,其形参类说明符是struct map_desc *,是一个指向结构体map_desc的指针。,.,5.4 函数,3内联函数 内联函数与一般函数不同的是,它不是在
36、调用时发生转移,而是在编译时将函数体嵌入在每一个调用语句处。这样就相对节省了参数传递、系统栈的保护与恢复等的开销。 内联函数的定义形式为: (含类型说明的形参表) 函数体 ,.,5.4 函数,例5.12 内联函数例题。 #include #include inline int max(int a,int b) if(ab) return a; else return b; ,void main() int a,b,c,d; a=210; b=150; c=20; d=max(a,b); d=max(d,c); /编译时两个调用处均被替换为max函数体语句 printf(The biggest
37、of %d %d %d is %d, a,b,c,d) ,程序运行结果为 The biggest of 210 150 20 is 210,.,5.4 函数,4系统函数的使用 系统函数的原型声明由系统提供,并且已分类存于不同的头文件中。 用include指令嵌入相应头文件,然后可使用系统函数。include指令格式如下。 # include 其中:头文件名可带或不带路经,尖括号内为标准头文件,由开发环境或系统提供。若头文件为用户自定义头文件,则头文件在双引号内。,例5.13 标准头文件定义 # include # include string.h和types.h是标准头文件,按环境变量 inc
38、lude指定的目录顺序搜索string.h和types.h。,.,5.4 函数,4系统函数的使用 系统函数的原型声明由系统提供,并且已分类存于不同的头文件中。 用include指令嵌入相应头文件,然后可使用系统函数。include指令格式如下。 # include 其中:头文件名可带或不带路经,尖括号内为标准头文件,由开发环境或系统提供。若头文件为用户自定义头文件,则头文件在双引号内。,例5.13 标准头文件定义 # include # include string.h和types.h是标准头文件,按环境变量 include指定的目录顺序搜索string.h和types.h。,.,5.5 数组
39、,1. 一维数组 (1) 数组的定义 数组在使用前必须先声明。 声明一个一维数组的形式如下: 数组长度 注意:数组长度是个常量表达式。 数组中的每个元素可以当成普通的变量使用。 访问一维数组元素的形式如下: 下标 注意:下标的值也是从0开始,不能超过该维的长度减1。,.,5.5 数组,(2)数组的初始化 数组的初始化有以下几种方式。 形式1:定义时整体初始化 与变量在定义时初始化一样,数组也可以在定义时进行初始化,格式如下: 数组长度=第0个元素值,第1个元素值,第n-1个元素值; 例如对字这符数组进行初始化: char a10=a,b,c,d,e,f,g,h,j,k;,.,5.5 数组,形式
40、2:定义时部分初始化 数组在定义时可对其中的部分数据进行初始化。 当“”中值的个数少于元素个数时,只给前面部分元素赋值。 例如如下定义就是对数组的前5个数据初始化,而后5个数据自动赋0(在字符数组中自动赋 0)。 char a10=a,b,c,d,e;,.,5.5 数组,形式3:数组全部赋值 若想要对数组中元素全部赋值,则可以省略数组下标中的常数,在此时,编译器会自动定义数组元素的个数,其格式如下: =第0个元素值,第1个元素值,第n个元素值; 例如: char a = a,b,c,d,e,f,g,h,j,k;,.,5.5 数组,2. 多维数组 (1)多维数组的定义 多维数组的声明形式如下:
41、长度1长度2 长度n (2)多维数组的引用 多维数组中元素的引用和一维数组的引用很相似,可通过下标引用的方式进行的。 其表示形式为: 第1维下标第2维下标第n维下标,.,5.5 数组,(2)多维数组的初始化 以下是二维数组的初始化形式: 形式1:分段赋值 第1维长度第2维长度=第0个第2维数据组,第1个第2维数据组,第n-1个第2维数据组 其中,n等于第1维长度。 形式2:按行连续赋值 第1维长度第2维长度=第0个元素值,第1个元值,第m个元素值 其中,m小于或等于第1维长度第2维长度。,.,5.5 数组,3. 数组作为函数的参数 将整个数组作为参数传递给函数,可通过传递不带方括号的数组名来进
42、行,其形式大体上有以下两种: 形式1: (类型标识符 数组名,int长度) 形式2: (类型标识符 数组名长度),.,5.5 数组,4. 数组与字符串 (1)字符数组的初始化 有两种特殊的初始化方法,形式如下: 形式1: char =字符串 形式2: char =字符串 两种形式效果相同,且在末尾加个“0” ,例如: char pMyStrinq=This is a computer; 它等同于: char pMyString=T,h,i,s, ,a, ,c,o,m,p,u,t,e,r,0; 或 char pMyStrinq=This is a computer;,.,5.5 数组,(2)字符
43、串的基本运算 求字符串的长度 假设字符串保存在数组pString中,求字符串长度的程序代码如下: char pString=abcd; int nSize=0; while(pStringnSize!= 0) nSize+; 执行完毕后,整型变量nSize中保存的值就是字符串pString的长度。,.,5.5 数组, 字符串的复制 假设源字符串保存在数组pSource中,目的字符型数组为pDestination,则字符串复制的程序段如下: char pSource=abcd; char pDestination=5; /源字符串长度+1 int nIndex=0; while(pSourcen
44、Size!=0) pDestinationnIndex=pSourcenIndex; nIndex+; pDestinationnIdex= 0; /标识字符串结束,.,5.5 数组, 字符串的连接 假设源字符串保存在字符数组pDest中,要连接进来的字符串保存在字符数组pTocat中,则程序代码为: char pTocat=efg; char pDest8=abcd; int nSize=0; int nIndex=0; while (pDestnSize!=0) /找到被要连接的字符串的尾部 nSize+; do pDestnSize+=pTocatnIndex; nIndex+; whi
45、le(pTocatnIndex!= 0); pDestnSize= 0;,.,(3)字符串处理函数,要引入#include 语句,.,(3)字符串处理函数,要引入#include 语句,.,5.5 数组, 字符串的连接 假设源字符串保存在字符数组pDest中,要连接进来的字符串保存在字符数组pTocat中,则程序代码为: char pTocat=efg; char pDest8=abcd; int nSize=0; int nIndex=0; while (pDestnSize!=0) /找到被要连接的字符串的尾部 nSize+; do pDestnSize+=pTocatnIndex; nI
46、ndex+; while(pTocatnIndex!= 0); pDestnSize= 0;,.,5.8 汇编语言与C/C+的混合编程,汇编语言与C/C+的混合编程 在C/C代码中嵌入汇编指令。 在汇编程序和C/C的程序之间进行变量的互访。 汇编程序、C/C程序间的相互调用。,.,5.8 汇编语言与C/C+的混合编程,5.8.1 内嵌汇编指令 是嵌入在C/C+程序中使用,但不能直接引用C语言的变量定义,数据交换必须通过ATPCS进行。 1内嵌汇编指令的语法格式 _asm _ (“instruction . instruction”); /Linux gcc中支持 _asm instructio
47、n instruction ; /ADS中支持 特别注意:是“_asm ”是两个下划线。,.,5.8.1 内嵌汇编指令,2内嵌汇编指令的特点 (1)操作数 内嵌的汇编指令中作为操作数的寄存器和常量可以是C/C+表达式。是char、short、int类型,而且这些表达式都是作为无符号数进行操作。 编译器将会计算这些表达式的值,并为其分配寄存器。,.,5.8.1 内嵌汇编指令,(2)物理寄存器 内嵌汇编指令中使用物理寄存器的限制: 不能直接向PC寄存器中赋值,程序的跳转只能通过B指令和BL指令实现。 在内嵌汇编指令中,不要使用过于复杂的C/C+表达式。 编译器可能会使用R12寄存器或R13寄存器存
48、放编译的中间结果,在计算表达式值时可能会将寄存器R0到R3、R12以及R14用于子程序调用。 指令中不要使用指定的物理寄存器。,.,5.8.1 内嵌汇编指令,(3)常量 在内嵌的汇编指令中,常量前的符号#可省略。若表达式前使用了符号#,则必须是一个常量。 (4)指令展开 内嵌的汇编指令中如果包含常量操作数,该指令可能会被汇编器展开成几条指令。例如指令: ADD R0,R0,#1023 可能会被展开成下面的指令序列: ADD R0,R0,#1024 SUB R0,R0,#01 MUL指令会被展开成一系列加法和移位操作。,.,5.8.1 内嵌汇编指令,(5)标号 C/C+程序中的标号可被内嵌的汇编
49、指令使用。但只有B指令可使用C/C+程序中的标号,指令BL不能使用C/C+程序中的标号。 指令B使用C/C+程序中的标号格式: Bcond label (6)内存单元的分配 所用的内存单元的分配都是通过C/C+程序完成的,分配的内存单元通过变量供内嵌的汇编器使用。,.,5.8.1 内嵌汇编指令,(7)SWI和BL指令的使用 内嵌SWI和BL指令中3个可选寄存器列表 第1个寄存器列表中的寄存器用于存放输入的参数。 第2个寄存器列表中的寄存器用于存放返回的参数。 第3个寄存器列表中的寄存器的内容可能被被调用的子程序破坏,即这些寄存器是供被调用的子程序作为工作寄存器。,.,5.8.1 内嵌汇编指令,
50、3内嵌的汇编器与armasm的区别 在功能和使用方法上主要有以下特点: 不能写PC (mov pc,lr) 不支持伪指令LDR Rn,=expression,但可用指令: LDR Rn,expression来代替。 除nop外,不支持ADR、ADRL等伪指令。 指令中的C变量不要与任何物理寄存器重名 LDM/STM指令中的寄存器列表只能使用物理寄存器,不能使用C表达式 不支持指令BX/BLX 用户不用维护数据栈 不要轻易改变处理器模式。 不支持内存分配操作,.,5.8.1 内嵌汇编指令,4内嵌汇编指令的应用举例 下面是在ADS 1.2下编译通过程序,程序中内嵌汇编指令。 例5.14 字符串复制
51、 本例中使用了指令BL调用子程序。在内嵌的BL指令中,除了正常的操作数外,还必须增加以下三个可选的寄存器列表: 第1个用于存放输入的参数 第2个用于存放返回的结果 第3个作为子程序的工作寄存器,程序代码如下: #include void my_strcpy(char* src, const char* dst) int ch; _asm loop: LDRB ch, src, #1 STRB ch, dst, #1 CMP ch, #0 BNE loop ; ,int main(void) const char* a = Hello World!; char b20; _asm MOV R0,
52、 a MOV R1, b BL my_strcpy, R0, R1 ; printf(Original String: %sn,a); printf(“Copied String: %sn,b); return 0; ,例中主函数main(void)中的BL my_strcpy, R0, R1指令的输入寄存器列表为R0, R1;它没有输出寄存器列表; 被子程序使用的工作寄存器为ATPCS的默认工作寄存器R0R3、R12、lr以及PSR。,.,5.8.1 内嵌汇编指令,例5.15 使能和禁止中断 本例主要介绍怎样利用内嵌的汇编程序实现使能和禁止中断。 通过修改CPSR寄存器中的bit7可使能和禁
53、止中断。但这些操作必须在特权模式下进行,因为在用户模式下不能修改寄存器CPSR中的控制位。源程序代码如下。,程序代码如下: _inline void enable_IRQ(void) int tmp; _asm MRS tmp,CPSR BIC tmp, tmp, #0 x80 MSR CPSR_c, tmp ,_inline void disable_IRQ(void) int tmp; _asm MRS tmp, CPSR ORR tmp, tmp, 0 x80 MSR CPSR_c, tmp int main(void) disable_IRQ( ); enable_IRQ( ); ,.
54、,5.8.2 从汇编程序中访问C程序变量,在C程序中声明的全局变量可被汇编程序通过地址间接访问。具体访问方法如下: 使用IMPORT伪操作声明该全局变量。 使用LDR伪指令读取该全局变量的内存地址,通常该全局变量的内存地址值存放在程序的数据缓冲池中(literal pool)。 根据该数据的类型,使用相应的LDR指令读取该全局变量的值;使用相应的STR指令修改该全局变量的值。,.,5.8.2 从汇编程序中访问C程序变量,各数据类型及对应的LDR/STR指令如下: 对于无符号的char类型变量通过指令LDRB/STRB来读/写。 对于无符号的short类型变量通过指令LDRH/STRH来读/写。
55、 对于int类型的变量通过指令LDR/STR来读/写 对于有符号的char类型的变量通过指令LDRSB来读取。 对于有符号的char类型的变量通过指令STRB来写入。 对于有符号的short类型的变量通过指令LDRSH来读取。 对于有符号的short类型的变量通过指令STRH来写入。 对于小于8个字的结构型变量,可以通过一条LDM/STM指令来读/写整个变量。 对于结构型变量的数据成员,可以使用相应的LDR/STR指令来访问,这时必须知道该数据成员相对于结构型变量开始地址的偏移量。,.,5.8.2 从汇编程序中访问C程序变量,例5.16 从汇编程序中访问C程序全局变量 在汇编程序中访问C程序全
56、局变量。 程序中变量globvl是在C程序中声明的全局变量。在汇编程序中首先用IMPORT伪操作声明该变量;将其内存地址读入到寄存器R1中;再将其内存单元中的值读入到寄存器R0中;修改后再将寄存器R0的值赋于变量globvl。,.,5.8.2 从汇编程序中访问C程序变量,例5.16 从汇编程序中访问C程序全局变量 源程序代码如下: AREA globals, CODE, READONLY EXPORT asmsub IMPORT globvl asmsub LDR r1, =globvl LDR r0, r1 ADD r0, r0, #2 STR r0, r1 MOV pc, lr END,.
57、,5.8.3 编程序与C/C+程序的相互调用规则ARPCS,ATPCS(ARM-Thumb Procedure Call Standard)规则。 1寄存器的使用规则 寄存器的使用必须满足下面规则: 子程序间通过寄存器R0R3来传递参数,记为A1A4。被调用的子程序在返回前无须恢复寄存器R0R3的内容。 子程序中使用寄存器R4R11来保存局部变量。记为V1V8。如果在子程序中使用到了寄存器V1V8中的某些寄存器,则子程度进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值;对于子程序中没有用到的寄存器,则不必进行这些操作。在Thumb程序中,通常只能使用寄存器R4R7来保存局部变量。,
58、.,5.8.3 汇编程序与C/C+程序的相互调用规则ARPCS, 寄存器R12用作子程序间的scratch寄存器,常用于子程序间的连接代码段中,记作IP。 寄存器R13用作数据栈指针,记作SP。在子程序中寄存器R13不能用作其他用途。寄存器SP在进入子程序时的值和退出子程序时的值必须相等。 寄存器R14称为链接寄存器,记作LR。它用于保存子程序的返回地址。如果在子程序中保存了返回地址,则寄存器R14可作其他用途。 R15是程序计数器,记作PC。不能作其他用途。,.,5.8.3 汇编程序与C/C+程序的相互调用规则ARPCS,.,5.8.3 汇编程序与C/C+程序的相互调用规则ARPCS,2数据栈的使用规则 有下面4种数据栈: FD(Full Descending) 满递减; ED(Empty Descending) 空递减; FA(Full Ascending) 满递增; EA(Empty Ascending) 空递增。,.,5.8.3 汇编程序与C/C+程序的相互调用规则ARPCS,ATPCS规定数据栈为FD(满递减)类型,并且对数据栈的操作是8字节对齐的。异常中断的处理程序可使用中断程序的数据栈。 数据栈指针(Stack Point):最后一个写入栈的数据的内存地址。 数据栈的基地址(Stack Base):数据栈的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026云南地矿工程勘察集团有限公司第一次招聘13人参考题库(精练)附答案详解
- 2026浙江杭州萧山颐乐养老集团有限公司合同制员工招聘4人备考题库含完整答案详解【夺冠系列】
- 2026年西安经开第十小学教师招聘笔试题库及参考答案详解【夺分金卷】
- 防疫版语文试题及答案
- 2026天津市面向甘南籍未就业高校毕业生招聘事业单位40人备考题库含答案详解(突破训练)
- 内镜三基试题及答案
- 低压电工安全试题及答案
- 林业有害生物防治员考试题及答案
- 元宇宙虚实结合体验升级
- 2026江西省赣房投资集团有限公司中层管理人员招聘1人备考题库附参考答案详解(黄金题型)
- 2026银行遴选面试题及答案
- 2026乌鲁木齐城市轨道集团招聘(191人)笔试参考题库及答案详解
- 2026年非遗文化赋能数字化乡村振兴现状调研报告
- 华中科技大学2026年强基计划校考(面试+体育测试)模拟试题及答案解析
- 2021版220kV厂站二次接线标准图纸集
- NB-T35026-2022混凝土重力坝设计规范
- 夏令营教官业务培训
- T-CROPSSC 009-2023 茎尖菜用甘薯生产技术规程
- 2023学年度高一下学期班主任工作总结
- 绿化苗木主材采购(供货计划、售后服务承诺)
- YY/T 0696-2021神经和肌肉刺激器输出特性的测量
评论
0/150
提交评论