【C语言资料更新】第六十一集 结构体存储和用typedef定义结构体存储类型
结构体内部成员变量存储
前一小节,我们通过一个简单的例子来学习了结构体的定义和使用。事实上,结构体相当于是把一系列存在某种内在逻辑关系的变量成员包含在一个特定的群组中,从而实现便捷的变量访问。但是,一旦一个结构体变量被定义好之后,结构体内部成员变量之间的关系就不仅仅只是逻辑上的关系了,在实际内存编排中,它们也是被顺序安排的,但结构体的内存不同于数组的那种连续,虽然一个结构体内部的成员是按顺序排列的,但是它们的地址却不一定会连续。为证明这个,我们可以写一个程序,定义一个结构体,一次将其内部成员变量的地址打印出来。如图7-2-1所示。
图7-2-1 结构体成员变量地址输出
从图7-2-2程序的输出,我们可以看到,结构体成员第一个变量Var_A的起始地址是6684160,由于其是int数据类型,所以向后占用4个地址的字节,其占用的地址应该为:6684160,6684161,6684162,6684163。当编排到Var_B时,它的内存起始地址应该从6684164开始,由于Var_B是char类型,因此其占1个地址的字节,即6684164。Var_C也一样,占用1个地址的字节,即6684165。接下来是Arr_A,由于这个数组的类型是short在这个MinGW里面的长度为2个字节,而Arr_A是个长度为2的数组,因此其占用4个地址的字节,内存地址应该为6684166,6684167,6684168,6684169。Arr_B的起始地址按照理论应该为6684170,但是我们却发现,实际上存储时,它的地址变成了6684172,这就证明了结构体内部成员变量的地址虽然是顺序排列的,但是并不连续。关于结构体地址的排列原则,每个编译器标准都不一样,我们只需要知道“结构体内部成员变量的地址虽然是顺序排列的,但是并不连续”这一条即可。不过这不是绝对的,等后面讲述了共用体,我们再来回顾这个知识点。
typedef关键词的使用
一般我们定义结构体有两种方法,第一种是将结构体标签声明和结构体变量定义放在一起去实现,这种方式的好处是代码精简,适合临时定义结构体变量时去使用。
第二种方式是先声明一个结构体标签,接着再用这个结构体标签去定义新的结构体变量,使用这种方式就可以去重复定义结构体了,但是每次定义结构体时都需要写成“struct结构体标签 结构体变量名”这样的方式,显得太过麻烦。
那么有没有什么办法可以使得第二种方法变得更精简些呢?这里就要介绍到C语言里面的另一个重要的关键词了——typedef。
typedef是在C语言中用来为复杂的声明定义简单的别名,它与宏定义“#define”有些差异。它本身是一种存储类的关键字,与auto、extern、static、register等关键字不能出现在同一个表达式中。说简单点,typedef可以将关键词简化。它的使用形式为:
typedef (简单或者复合)数据类型 新的数据类型名;
注意,使用typedef时,语句最后的分号千万不能忘记。
比如,当我们在使用C语言需要定义一个以字节为单位的变量时,使用unsignedchar写起来非常麻烦,那么我们就可以使用typedef关键词将unsigned char类型直接改写成BYTE,此时就可以定义:
typedef unsigned char BYTE;
定义好BYTE数据类型之后,我们就可以使用它去作为数据类型定义新的变量了,如:
BYTE Data;
再如,一般阅读嵌入式程序时,经常会出现u8(无符号8为存储类型),u16(无符号16为存储类型),u32(无符号32为存储类型)之类的存储类型,其实这些都是使用typedef来定义的数据类型。我们可以写出代码,将这些存储类型一一定义出来,并且使用sizeof关键词测量出其长度。如图7-2-2所示。
图7-2-2 typedef定义新的数据类型
使用typedef关键词定义结构体存储类型
了解了typedef的使用之后,我们思考下,是否我们也可以使用typedef关键词将不同的结构体声明定义成不同的数据类型呢?
首先我们来看一种结构体变量定义的方式,假设我要定义一个结构体来存储一本书的特征并且定义两本书,那么可以写成:
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} Book1, Book2;
或者
struct
{
char title[50];
char author[50];
char subject[100];
int book_id;
} Book1, Book2;
其实这两种方式一样,只不过第二种省略了结构体标签。
对于结构体定义简化来说,我们的理想形式是这样子的:
书结构体类型 Book1, Book2。
那么如果要写成这种方式,我们就需要将上述两种定义的红色部分替换掉。而这个代码中的红色部分就是一种存储类型,正好适合用typedef来定义,因此我们就可以用typedef来定义一个新的类型。
typedef struct
{
char title[50];
char author[50];
char subject[100];
int book_id;
} Book_t;
定义好之后,一个新的类型Book_t就出现了,以后,我们就都可以使用Book_t去定义书本相关的变量了:
Book_t Book1, Book2;
对于我们用typedef新定义的数据类型,习惯使用“_t”的形式结尾。
基于上述内容,我们写一些相关的代码,假设有两个小孩子,小明,小丽,写一个代码将他们的身高体重描述出来。如图7-2-3所示。
图7-2-3 结构体类型定义