struct:
作用:将一些不同或相同类型变量封装在一起建立一个新的类型。
内存:等于内部成员变量内存之和
struct Point
{
double x;
double y;
double z;
};
常见错误定义方式
/* 错误方式 */
struct tag_1
{
struct tag_1 A;
int value;
};
原因在自引用结构体时无法确定结构体长度:
内部成员A也是结构体tag_1,A自己的内部有成员也是结构体tag_1,进入无限循环,无法确定结构体长度
/* 改进方式 */
struct tag_1
{
struct tag_1 *A;
int value;
}
原因在于指针长度是固定的,结构体长度可以确定:
一般来说,在64位系统下,指针长度为8,32位系统下,指针长度为4;
但有的编译器为了不同的操作系统之间相互兼容,内部对指针进行了包装,使得不管是64位还是32位系统下,指针都是4个字节长度
总而言之,在特定系统下的的指针长度是固定的。
使用:如果我们要调用这个结构体,必须像这样,才能调用结构体。(定义变量时必须加上struct关键字,这样调用显得有些冗杂,而后则可以通过typedef定义结构体类型,直接调用,可由下文typedef作用1可见)
struct Point oPoint1={100,100,0};
struct Point oPoint2;
typedef:
作用:
1)为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型名称。
(也就是说,无论是否具有typedef关键词,此结构体都是存在的,只是typedef提供了一个方便调用的别名)
常用的,就是为结构体提供一个别名,如:
typedef struct tagPoint
{
double x;
double y;
double z;
}Point;
//调用时,无需再加struct,相当于通过typedef关键词定义了一个新的类型
Point oPoint1={100,100,0};
Point oPoint2;
调用注意事项:
/* 正确的定义方式 */
typedef struct tag_1
{
int value;
struct tag_1 *link;
} NODE;
struct tag_2;
typedef struct tag_2 NODE;
struct tag_2
{
int value;
NODE *link;
};
struct tag_3
{
int value;
struct tag_3 *link;
};
typedef struct tag_3 NODE;
//与方式二相比,更推荐方式三
/* 常见错误定义方式 */
typedef struct tagNode
{
char *pItem;
pNode pNext;
} *pNode;
错误原因:pNode表示的是该结构体的新别名,而只有在整个结构体建立完毕后,这个别名才成立
所以,在结构类型本身还没有建立完成的时候,编译器根本就不认识pNode,也就是这个结构体类型的新别名还不存在
/* 改进方式 */
//所谓改进方式,其实前面提及的三种正确方式都可
typedef struct tagNode
{
char *pItem;
struct tagNode *pNext;
} *pNode;
2)为基本数据类型、数组、指针定义新的简洁的类型名
在一些比较长、常用、对编写者而言具有特定意义的数据类型时,很有用
/* 为基本数据类型定义别名 */
//如果需要改变REAL的类型可以直接修改,自定义新名称的数据类型也更便于编译者明确变量的设计意图
typedef unsigned int REAL;
typedef long double REAL;
/* 为数组定义简洁别名 */
typedef int INT_ARRAY_100[100];
INT_ARRAY_100 arr;
/* 为指针定义简洁别名 */
// PFun是我们创建的一个类型别名
typedef int *(*PFun)(int,char*);
// 使用定义的新类型来声明对象,等价于int*(*a[5])(int,char*);
PFun a[5];
注意:
1)defef不同于#define:#define是宏,是字符串的替换,但是defef则是定义的新数据类型(别名)因此:
typedef char* PCHAR;
int strcmp(const PCHAR,const PCHAR);
const PCHAR ≠ const char*(指向常量char的指针)
PCHAR typedef定义了PCHAR数据类型,此数据类型为(char *)的别名
∴const PCHAR = const (char*)(指向char的常量指针)
2)虽然 typedef 并不真正影响对象的存储特性,但在语法上它还是一个存储类的关键字,就像 auto、extern、static 和 register 等关键字一样(同类关键字不可重复多用)。因此,像下面这种声明方式是不可行的:
typedef static int INT_STATIC;
union:
作用:节省内存空间,使共用体体内的变量共用一个地址空间首地址,总的来说,就是开辟一个共有内存首地址,共用体内部的各种变量同时使用,操作共同生效。
内存:等于内部成员中内存最大的那个变量的内存大小
本质:固定首地址+按最大需求开辟一段内存空间
适用场景:各数据类型各变量占用空间差不多并且对各变量同时使用要求不高的场合
(比如说,浮点型和四个字节的转换中)
union foatWBity
{
float y1;//浮点型
char y2[4];//浮点型数据对应的四个字节
}floatWBity1;
补充:
1)定义共用体、结构体时,如果在函数内部,定义时相当于一个语句,需要加“;”,如果是在函数外全局定义,没有必要加“;”
2)关于为什么指针的内存大小固定:
以64位系统下,一个指针长度一般为8为例,64位系统,这个位数指的是CPU内的通用寄存器的数据宽度为64位,即一个地址占二进制位数为64,一个指针其实就是一个地址,所以,一个指针的大小,就是一个地址的大小:64位=8字节
sizeof(double *)==sizeof(int *)==sizeof(char*)==64/8==8
(除8是因为sizeof()计算的为某个数据类型所占的字节个数,而一个字节是八位二进制)
如果那里有理解错误的地方,欢迎讨论指正~
参考资料:
(C/C++学习)23.C++中指针的长度 - 退後。 - 博客园 (cnblogs.com)
结构体的嵌套问题 - 任智康 - 博客园 (cnblogs.com)
typedef的用法,C语言typedef详解 (biancheng.net)
(35条消息) 结构体struct和联合体union最全讲解_liguangxian2018的博客-CSDN博客_结构体和联合体