typedef 与 #define 比较
typdef 的一些特性与 define 的功能重合。例如:
#define BYTE unsigned char
这是预处理器用 BYTE 替换 unsigned char。
但也有 #define 没有的功能,例如:
typedef char * STRING;
编译器把 STRING 解释为一个类型的表示符,该类型指向 char。因此:
STRING name, sign;
相当于:
char * name , * sign;
但是,如果这样假设:
#define STRING char *
然后,下面的声明:
将被翻译成:
char * name, sign;
这导致 name 才是指针。
简而言之,#define 只是字面上的替换,由预处理器执行,#define A B 相当于打开编辑器的替换功能,把所有的 B 替换成 A。
与 #define 不同,typedef 具有以下三个特点:
typedef 与 #define 的区别
(1)#define可以使用其他类型说明符对宏类型名进行扩展,但对 typedef 所定义的类型名却不能这样做。例如:
#define INTERGE int; unsigned INTERGE n; //没问题 typedef int INTERGE; unsigned INTERGE n; //错误,不能在 INTERGE 前面添加 unsigned
(2) 在连续定义几个变量的时候,typedef 能够保证定义的所有变量均为同一类型,而 #define 则无法保证。例如:
#define PTR_INT int * PTR_INT p1, p2; //p1、p2 类型不相同,宏展开后变为int *p1, p2; typedef int * PTR_INT PTR_INT p1, p2; //p1、p2 类型相同,它们都是指向 int 类型的指针。
补充楼上 @karma,位域的内存大小测试
// 位域内存测试 #include <STDIO.H> struct ONE_BYTE { unsigned char _bool : 1; unsigned char del_flag : 1; unsigned char status : 4; } one_byte; struct TWO_BYTE { unsigned char ccc1 : 4; unsigned char ccc2 : 4; unsigned char ccc3 : 4; unsigned char ccc4 : 4; } two_byte; struct THREE_BYTE { unsigned char ccc1 : 4; unsigned char ccc2 : 4; unsigned char ccc3 : 4; unsigned char ccc4 : 4; unsigned char ccc5 : 4; } three_byte; struct FOUR_BYTE { unsigned int ccc1 : 16; unsigned int ccc2 : 16; } four_byte; struct EIGHT_BYTE { unsigned char ccc1 : 1; unsigned int ccc2 : 1; } eight_byte; int main(int argc, char const *argv[]) { printf("sizeof one_byte is : %dB\n", sizeof(one_byte)); printf("sizeof two_byte is : %dB\n", sizeof(two_byte)); printf("sizeof three_byte is : %dB\n", sizeof(three_byte)); printf("sizeof four_byte is : %dB\n", sizeof(four_byte)); printf("sizeof eight_byte is : %dB\n", sizeof(eight_byte)); return 0; }
输出结果为:
sizeof one_byte is : 1B sizeof two_byte is : 2B sizeof three_byte is : 3B sizeof four_byte is : 4B sizeof eight_byte is : 8B
由输出,可以验证以下结论:
(1)结构体内存分配原则:
(2)定义位域时,各个成员的类型最好保持一致,比如都用char,或都用int,不要混合使用,这样才能达到节省内存空间的目的。
结构体内存分配原则
原则一:结构体中元素按照定义顺序存放到内存中,但并不是紧密排列。从结构体存储的首地址开始 ,每一个元素存入内存中时,它都会认为内存是以自己的宽度来划分空间的,因此元素存放的位置一定会在自己大小的整数倍上开始。
原则二: 在原则一的基础上,检查计算出的存储单元是否为所有元素中最宽的元素长度的整数倍。若是,则结束;否则,将其补齐为它的整数倍。
测试实例:
#include <stdio.h> typedef struct t1{ char x; int y; double z; }T1; typedef struct t2{ char x; double z; int y; }T2; int main(int argc, char* argv[]) { printf("sizeof(T1) = %lu\n", sizeof(T1)); printf("sizeof(T2) = %lu\n", sizeof(T2)); return 0; }
输出:
sizeof(T1) = 16 sizeof(T2) = 24
解析
sizeof(T1.x) = sizeof(T2.x) = 1; sizeof(T1.y) = sizeof(T2.y) = 4; sizeof(T1.z) = sizeof(T2.z) = 8;
T1: 若从第 0 个字节开始分配内存,则 T1.x 存入第 0 字节,T1.y 占 4 个字节,由于第一的 4 字节已有数据,所以 T1.y 存入第 4-7 个字节,T1.z 占 8 个字节,由于第一个 8 字节已有数据,所以 T1.z 存入 8-15 个字节。共占有 16 个字节。
T2: 若从第 0 个字节开始分配内存,则 T1.x 存入第 0 字节,T1.z 占 8 个字节,由于第一的 8 字节已有数据,所以 T1.z 存入第 8-15 个字节,T1.y 占 4 个字节,由于前四个 4 字节已有数据,所以 T1.z 存入 16-19 个字节。共占有 20 个字节。此时所占字节不是最宽元素(double 长度为 8)的整数倍,因此将其补齐到 8 的整数倍,最终结果为 24。
文中例子解析:
struct { unsigned int age : 3; } Age; /*age 变量将只使用 3 位来存储这个值,如果您试图使用超过 3 位,则无法完成*/ Age.age = 4; printf("Sizeof( Age ) : %d\n", sizeof(Age)); printf("Age.age : %d\n", Age.age); // 二进制表示为 111 有三位,达到最大值 Age.age = 7; printf("Age.age : %d\n", Age.age); // 二进制表示为 1000 有四位,超出 Age.age = 8; printf("Age.age : %d\n", Age.age);
如果超出范围,则直接丢掉了,存不进去。
感谢您的支持,我会继续努力的!
支付宝扫一扫,即可进行扫码打赏哦
1534C typedef
typedef 与 #define 比较
typdef 的一些特性与 define 的功能重合。例如:
这是预处理器用 BYTE 替换 unsigned char。
但也有 #define 没有的功能,例如:
编译器把 STRING 解释为一个类型的表示符,该类型指向 char。因此:
相当于:
但是,如果这样假设:
然后,下面的声明:
将被翻译成:
这导致 name 才是指针。
简而言之,#define 只是字面上的替换,由预处理器执行,#define A B 相当于打开编辑器的替换功能,把所有的 B 替换成 A。
与 #define 不同,typedef 具有以下三个特点:
1533C typedef
typedef 与 #define 的区别
(1)#define可以使用其他类型说明符对宏类型名进行扩展,但对 typedef 所定义的类型名却不能这样做。例如:
(2) 在连续定义几个变量的时候,typedef 能够保证定义的所有变量均为同一类型,而 #define 则无法保证。例如:
1532C 位域
补充楼上 @karma,位域的内存大小测试
输出结果为:
由输出,可以验证以下结论:
(1)结构体内存分配原则:
(2)定义位域时,各个成员的类型最好保持一致,比如都用char,或都用int,不要混合使用,这样才能达到节省内存空间的目的。
1531C 位域
结构体内存分配原则
原则一:结构体中元素按照定义顺序存放到内存中,但并不是紧密排列。从结构体存储的首地址开始 ,每一个元素存入内存中时,它都会认为内存是以自己的宽度来划分空间的,因此元素存放的位置一定会在自己大小的整数倍上开始。
原则二: 在原则一的基础上,检查计算出的存储单元是否为所有元素中最宽的元素长度的整数倍。若是,则结束;否则,将其补齐为它的整数倍。
测试实例:
输出:
解析
T1: 若从第 0 个字节开始分配内存,则 T1.x 存入第 0 字节,T1.y 占 4 个字节,由于第一的 4 字节已有数据,所以 T1.y 存入第 4-7 个字节,T1.z 占 8 个字节,由于第一个 8 字节已有数据,所以 T1.z 存入 8-15 个字节。共占有 16 个字节。
T2: 若从第 0 个字节开始分配内存,则 T1.x 存入第 0 字节,T1.z 占 8 个字节,由于第一的 8 字节已有数据,所以 T1.z 存入第 8-15 个字节,T1.y 占 4 个字节,由于前四个 4 字节已有数据,所以 T1.z 存入 16-19 个字节。共占有 20 个字节。此时所占字节不是最宽元素(double 长度为 8)的整数倍,因此将其补齐到 8 的整数倍,最终结果为 24。
1530C 位域
文中例子解析:
如果超出范围,则直接丢掉了,存不进去。