首页 理论教育 嵌入式C程序设计:变量、数组、结构详解

嵌入式C程序设计:变量、数组、结构详解

时间:2023-11-23 理论教育 版权反馈
【摘要】:为了增加程序可读性和移植程序时的方便,C 语言允许用户为C 语言固有的类型用typedef 起别名。在作用范围内,外部变量可以被程序中的各个函数所用。内部静态变量在程序全程内存在,但只能在本函数内可存取。在C 语言中单独开辟一个常量区用于存放const 变量。若初值的个数少于常量表达式值,其后的缺省项由编译器自动以“0”值补之。

嵌入式C程序设计:变量、数组、结构详解

(1)变量

格式:

[存储类型] 类型说明符 [修饰符] 标识符[ =初值] [,标识符[ =初值]]…;

其中,各部分说明如下:

1)类型说明符

①对于数字与字符,其类型共有9 种:char、unsigned char、int、unsigned、long、unsigned long、float、double、long double。

②void 类型(抽象型),在具体化时可以用void 类型强制来指定类型说明符中的任意一类。

③通过typedef 定义的类型别名。 为了增加程序可读性和移植程序时的方便,C 语言允许用户为C 语言固有的类型用typedef 起别名。 其格式如下:

typedef C 固有的简单类型或复合类型 别名标识符;

用别名代替原来的类型,在说明中用作类型说明符。 别名一般用大写字符,例如:

2)标识符

①变量,是不带“*”的标识符。 编译器为变量自动分配内存。

指针,是带有“*”的标识符,指针的内容必须是地址。 编译器为指针自动分配内存。注意,指针标识符是不带“*”的标识符部分。 指针说明中的类型说明符、存储类型和修饰符是指针指向对象的类型。 一般所说“指针是变量”,即指针指向的对象是变量。 变量指针的类型可以是void。 例如:

extern int const *count;  /*count 是指针,而且是外部存储类型的整型常量*/

3)存储类型

存储类型指定被说明对象所在内存区域的属性。

①auto—自动存储类型,它是局部变量,也是在函数内定义的变量且仅在该函数内是可见的(可以是变量、指针以及函数的实参),放在内存的栈中。 其存储区随着函数的进入而建立,随着函数的退出而自动地被放弃。 在函数中说明的内部变量,凡未加其他存储类说明的都是auto 类型,每次调用该函数时都需要重新在堆栈中分配空间。

②register—寄存器存储类型,将使用频繁的变量放在CPU 的寄存器中,需要时直接从寄存器取值,而不必再到内存中去存取,以求处理高速

③extern—外部存储类型,表明该变量是外部变量(也称为“全局变量”),它是在函数外部定义的变量,它的作用域是为从变量的定义开始到本程序文件的末尾。 在作用范围内,外部变量可以被程序中的各个函数所用。 编译时外部变量被分配在静态存储区。 外部变量能否被存取,由该外部变量定义性说明与使用它的函数之间的位置关系来决定。 如果程序中只有一个文件,在定义了外部变量之后,使用该外部变量的函数则可直接存取;如果程序中有多个文件,在非该变量的定义文件中要使用它时,必须先加引用性说明,然后才能使用。 其引用性说明格式如下:

extern 类型说明符[修饰符] 变量名[,变量名]…;

在C 语言中,与外部变量对应的还有内部变量,在函数内部作定义性说明的变量都是内部变量,如前面所讲的auto 和register 存储类型变量。 内部变量只能在函数内部进行存取。

④static—静态存储类型,分为两种:内部静态和外部静态。 在函数内部定义变量并说明为静态存储类的是内部静态变量,在离开这个函数到下次调用之间内部静态变量的值保持不变。 内部静态变量在程序全程内存在,但只能在本函数内可存取。 在函数外部定义变量并说明为静态存储类型的是外部静态变量。 外部静态变量在程序全程内存在,但在定义它的范围以外,也是隐蔽起来的,是不可用的。 对于只有一个源文件的程序来说,如果在文件开始定义的外部变量,加与不加static 是一样的。

4)赋初值部分

若初值缺省,auto 存储类型和register 存储类型的变量为随机值;static 存储类型的变量被编译器自动清为“0”;对于指针,无论什么存储类型,一律置为空指针(NULL)。

使用等号为变量赋初值。 需要注意的是指针必须用地址量作为初值,字符可以用其编码值(例如ASCAII 码)或用单引号括起的字符作为初值。 对于静态变量,只在定义说明时赋初值一次。

5)修饰符

修饰符用于对变量进行特殊地修饰。 修饰符包括以下三类:

①const—常量修饰符,指示被修饰的变量或变量指针是常量。 在C 语言中单独开辟一个常量区用于存放const 变量。 注意变量被const 修饰后就不能再变了。 对于指针有两种修饰的方法,它们的意义是不同的,例如:

②volatile—易失性修饰符,说明所定义的变量或指针,是可以被多种原因所修改的。 例如,有的变量在中断服务程序中会被修改,有的会被I/O 接口修改,这种修改带有随机性,防止丢失任何一次这种修改,故要将它修饰为易失性的变量。 注意,禁止将它作为寄存器变量处理,也禁止对它进行任何形式的优化

③near,far 近、远修饰符,用于说明访问内存中变量在位置上的远近。

6)变量说明

①格式中带有“[]”的是可选项,可有可无,不带“[]”的是必须有的(以下格式与此相同)。

②在一个说明语句中可以同时说明多个同类型的变量。 这些变量之间要用逗号隔开,每个变量是否赋初值是任选的。

③说明语句一定要用终止符“;”结束。

示例:

有关变量的定义。

(2)数组说明

格式:

[存储类类型] 类型说明符[修饰符] 标识符[ =初值符][,标识符[ =初值]]…;

1)一维数组

格式:

类型说明符 标识符[常量表达式][ ={初值,初值,…}];

char 标识符[] =“字符串”;

标识符后跟方括号“[]”是一个一维数组的特征(注意,在这里方括号是必须的)。 定义时若数组未赋初值,当方括号在用于数组时,其括号内必须有常量表达式,表示为数组分配内存的大小。 初值缺省时,数组各元素为随机值;需赋初值时,使用等号进行赋初值,后面跟花括号“{}”,花括号内是用逗号分隔的初值表。 初值的个数要小于或等于常量表达式的值,初值为“0”的元素可以只用逗号占位而不写初值。 若初值的个数少于常量表达式值,其后的缺省项由编译器自动以“0”值补之。

字符型(char)数组是例外,它允许标识符后跟的方括号内为空,但必须赋初值。 赋初值用等号,初值是双引号括起的字符串。 字符数组的长度由编译器自动完成,其值为串中字符数加“1”(多结尾符‘\0’)。(www.xing528.com)

示例:

本例定义了八段数码管显示0 ~F 的符号数组,以及两个用于UART 操作中的字符型数组。

2)一维指针数组和一维数组指针

格式:

类型说明符 *标志符[常量表达式] [ ={地址,地址,…}];

类型说明符 (*标志符)[ ][ =数组标识符];

前者是一维指针数组,本质上是一个数组,只是它的元素是指针,即数组中存放的是其变量的地址,它在字符串排序中特别有用;后者是一维数组指针或称数组指针,本质上是一个指针,只是该指针指向的是一个数组。 指针指向数组的首地址,但是指针不能指向数组中的除首地址外的其他元素的地址。 也可以将数组指针理解为行指针,指针变化后可以指向二维数组不同的行。 数组指针不需要指明所指向的数组有多少元素。 下标方括号内可以是空的。在C 语言中,数组标识符并不代表整个数组,它只作为数组的首地址,即数组第一个元素的地址。 虽然指针变量的值是地址,但是指针和地址是有区别的。 指针是个对象,在内存中被分配有空间的,只不过该对象的内容不是变量而是可变的地址,而数组标识符只不过是已分配过内存的数组的首地址。

3)二维数组

格式:

类型说明符 标识符[m][n] [ ={{初值表},{初值表}…}];

上述格式是m×n 个元素的二维数组。 标识符独立使用时,它代表的是二维数组在内存中的首地址,与“&标识符[0][0]”意义相同。 数组标识符是一个地址常量,不能用作左值,可用在表达式中,而不可用于赋值运算符的左侧。 在C 语言中,二维数组在内存中的排列次序是先放第一行的n 列,再放第二行的n 列,直到第m 行的n 列。 赋初值的顺序也是按同样的序列。 初始化时,某些元素的初值可以省略,缺省初值被置为“0”。

4)二维指针数组

格式:

类型说明符 * 标识符[m][n][ ={{地址表},{地址表…}}];

上述格式是m×n 个元素的二维指针数组。 标识符单独使用时,它代表的是指针数组的首地址。 由于这个首地址的内容是指针,它指向的内容才是变量(地址变量)。 因此,指针数组标识符具有二重指针性质,是一个指针的指针。 指针数组标识符是一个地址常量,不可以用为左值,但可以为二维指针赋初值。

5)二维数组指针

格式:

类型说明符(* 标识符)[ ][n][ =数组标识符];

上述格式是一个二维数组的指针,这个指针指向的是一个二维数组,如前面的一维数组指针的介绍,只是二维数组指针所指向的数组是二维的。 为了使这个指针能指向二维数组的任一个元素,说明时应给出第二个方括号中的下标常量,至于第一个方括号中的下标量无须给出,给出也不为错。

6)多重指针

格式:

类型说明符 * * 标识符[ =&指针];

上述格式定义了一个多重指针变量,即指针的指针,可以用一个二维指针数组的标识符为它赋初值。

(3)结构说明

结构说明有原型法和类型别名法两种定义方法。

1)原型法

格式:

①声明结构类型的同时定义变量名

其中:存储类说明符有:static、extern;结构原型名有:结构名、*结构指针名。

②先声明结构类型再定义变量名

struct 结构原型名

[存储类说明符] struct 结构原型名 标识符[ ={初值表} [,标识符[ ={初值表}]…];

其中,存储类说明符有:static、extern;结构原型名有:结构名、*结构指针名。

2)类型别名法

先为结构原型名起别名,再用别名作定义说明。

格式:

[存储类说明符] 结构别名 标识符[ ={初值表} [,标识符[ ={初值表}]…];

其中:存储类说明符有:static、extern;结构原型名有:结构名、*结构指针名。 结构别名习惯上用大写字符。 [结构原型名]可用可不用,习惯上不用。 因为,一般说来,别名更具特色。

说明:

①结构由各种数据类型的成员组成。 成员之间没有次序关系,访问成员不按次序,而用结构成员名。

②成员可以是各种简单变量类型和复合变量类型,也可以是数组,数组的元素也可以是结构,即结构和数组可以互为嵌套

③只有在定义性说明时,才可以整体性地为结构赋初值。 在程序中,不能用语句整体性地给结构赋值,但可以对成员个别地进行赋值和取存操作。

④存取成员的方法有两种:a.结构名·成员名;b. 结构指针名—>成员名。 前者是结构首地址加偏移法,后者是指针值加偏移法。 只要结构指针指在结构的首地址上,二者就访问同一成员。

⑤对结构只能进行两种运算:一是对结构成员的访问;二是取结构的地址(&结构名)。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈