3.9 C语言的运行结构

1.数据类型

(见表3-1)

表3-1 数据类型

978-7-111-36320-0-Chapter03-34.jpg

①char等同于unsigned char。

floats和doubles是IEEE标准32位格式,7位表示指数,23位表示尾数,1位表示符号。位域类型必须被赋予unsigned或signed关键字,而且将被包含在一个较小的空间中。如可定义成结构:

978-7-111-36320-0-Chapter03-35.jpg

这个结构体的长度只有一个1B。位域是从右往左放置的。

2.汇编界面和调用规则

C语言中的名称在汇编文件中是以下划线为前缀的,如函数main()在汇编模块中是以_main()引用的。名称的有效长度为32个字符,在名称后面加两个冒号(::),可以定义成一个全局变量,例如:

978-7-111-36320-0-Chapter03-36.jpg

传递参数和返回值所使用的寄存器。第1个参数若是整型则通过R16/R17传递,第2个参数则通过R18/R19传递。如果参数是长整型或浮点数则通过R16/R17/R18/R19传递,其余参数通过软件堆栈传递。比如整型参数小的(如char)参数扩展成整型(int)长度传递,即使函数原型是可用的。如果R16/R17已传递了第1个参数,而第2个参数是长整型或浮点数,则第2个参数的低半部分通过R18/R19传递,而高半部分通过软件堆栈传递。

整型返回值是通过R16/R17返回,而长整型或浮点数返回则通过R16/R17/R18/R19返回。

在汇编函数中必须保护和恢复下列寄存器:R28/R29或Y,这是结构指针。R10/R11/R12/R13/R14/R15/R20/R21/R22/R23,这些寄存器是调用保护寄存器,这些寄存器的内容在被汇编语言函数调用后必须保持不变。

别的寄存器如R0/R1/R2/R3/R4/R5/R6/R7/R8/R9/R24/R25/R26/R27/R30/R31、SREG可以在汇编语言函数中使用,而不被保护和恢复。这些寄存器是调用挥发寄存器,这些寄存器的内容在被函数调用后可以改变。

对于它的中断处理,这不同于普通的函数调用,在中断操作中必须保护和恢复它所使用的全部寄存器。如果使用C函数来描述中断处理,那么编译器有能力自动完成。如果使用汇编写中断处理,而它又调用了普通的C函数,那么汇编操作必须保护和恢复挥发性寄存器,普通C函数调用不保护它们。中断处理操作同普通程序操作是异步的,中断处理或它的函数调用不能改变任意一个MCU寄存器。

3.函数返回非整型值

在调用函数前,必须描述其返回的一个长整型、浮点数或结构值。作为例子,在调用任意浮点函数之前,应当用#include语句包含头文件<math.h>。否则,在这些程序返回它们的值后程序将不工作,这与那些返回整型值的函数是有不同之处的。

长整型数或浮点数返回值设定在寄存器R16~R19中。如果传递结构值的话,结构允许通过堆栈传递,而不是通过寄存器。传递结构索引(也就是传递结构的地址)和传递任意数据项目的地址是相同的,都是通过一个2B的指针。对于返回结构值,当一个返回结构的函数被调用时,这个调用函数分配一个临时存储库,而且传递一个隐藏指针给调用函数。当这个函数返回时,它复制返回值到这个临时存储库。

4.程序和数据区的使用

程序存储器是被用于保存程序代码、常数表和确定数据的初始值,比如字符串、全局变量。编译器可以生成一个对应程序存储器映像的输出文件(HEX文件),这个文件可以被编程器用来对芯片编程。

通常,编译器不能使用任意64KB以上的程序存储器。为了访问64KB边界以上的存储器(如在Mega103装置中),要在设定RAMPZ寄存器后直接调用ELPM指令。

数据存储器(仅指内部SRAM),这个数据存储器是被用于保存变量、堆栈结构和动态内存分配的堆。通常,它们不产生输出文件,但在程序运行时使用,一个程序使用数据内存如图3-15所示。

978-7-111-36320-0-Chapter03-37.jpg

图3-15 数据存储器