自定义的类型:结构体

张开发
2026/4/13 12:47:15 15 分钟阅读

分享文章

自定义的类型:结构体
1.结构体类型的声明1.1结构声明struct tag { member-list; }variable-list;struct st { char name[20]; int age; char sex[5]; char id[20]; };1.1.1结构体变量的创建和初始化struct st { char name[20]; int age; char sex[5]; char id[20]; }; int main() { struct st u { zhangsan,20,nan,202456511325 }; printf(%s , u.name); printf(%d , u.age); printf(%s , u.sex); printf(%s , u.id); struct st u1 { .age 18,.name jiqiuyu,.id 2344532545,.sex nv }; printf(%s , u1.name); printf(%d , u1.age); printf(%s , u1.sex); printf(%s , u1.id); return 0; }1.2结构的特殊声明在声明结构时可以不完全声明struct { int a; char b; float c; }x; struct { int a; char c; float m; }a[20],*p;上面的两个结构在声明时省略了结构体的标签如果在上面的基础上 下面的代码合理吗px;是非法的匿名的结构体类型如果没有对结构体类型重命名的话只能使用一次1.3结构的自引用struct node { int dota; strcut node *next; }在自引用过程中能否夹杂重命名的匿名结构体变量肯定是不行的Node是对前面匿名结构体产生的但在里面就已经使用node来创建成员变量解决方案定义结构体时不使用匿名结构体typedef struct node { int data; struct node*next; }node;2.结构体内存对齐2.1对齐原则1.结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处2.其他成员变量要对齐到对齐数整数倍的地址处对齐数编译器默认的一个对齐数与该成员变量大小的较小值VS中默认值是83.结构体的总大小是最大对齐数的整数倍4.如果嵌套了结构体嵌套的结构体成员对齐到自己成员中最大对齐数的整数倍处结构体的整体大小是所有最大对齐数的整数倍练习1 struct S1 { char c1;//1 int i;//4 char c2;//1 }; int main() { printf(%d\n, sizeof(struct S1));//12 return 0; } 练习2 struct S1 { char c1;//1 char c2;//1 int i;//4 }; int main() { printf(%d\n, sizeof(struct S1));//8 return 0; } 练习3 struct S1 { double d;//8 char c;//1 int i;//4 }; int main() { printf(%d\n, sizeof(struct S1));//16 return 0; } 练习4 struct S3 { double d; char c; int i; }; struct S4 { char c1; struct S3 s3; double d; }; int main() { printf(%d\n, sizeof(struct S4));//32 return 0; }2.2为什么存在内存对齐1.平台原因不是所有硬件平台都能访问任意地址的任意数据某些硬件平台只能在某些地址处取得某些特定数据2.性能原因数据结构应该尽可能在自然边界对齐原因在于为了访问未对齐的内存处理器需要做俩次内存的访问而对齐的内存访问仅需要一次访问。假设一个处理器总是从内存中取8个字节则地址必须是8的倍数。如果能保证所有的double类型的数据地址都对齐成8的倍数那么就可以用一个内存操作来读或者写值。其实就是拿内存来换取时间。如果既想满足对齐又要节省空间可以让占用空间小的成员集中到一起struct S1 { char c1; int i; char c2; }; struct S2 { char c1; char c2; int i; }2.3修改默认对齐数#pragma可以修改编译器的默认对齐数#pragma pack(1) struct s { char s1; char s2; int s3; }; #pragma pack() int main() { printf(%zd, sizeof(struct s)); return 0; }结构体在对齐方式不合适时可以修改默认对齐数3.结构体传参struct c { int data[1000]; int num; }; struct c s { {1,2,3,4},1000 }; void print1(struct c s) { printf(%d,s.num); } void print2(struct c* ps) { printf(%d,ps-num); } int main() { print1(s); print2(s); }我们首选print2如果传递一个结构体对象时候结构体过大参数压栈的系统开销较大导致性能下降4.结构体实现位段4.1什么是位段位段的声明和结构是类似的1.位段的成员必须是intunsigned或者signed int。2.位段的成员名必须有一个冒号和数字struct a { int_a:20; int_b:5; };a就是一个位段类型4.2位段的内存分配1..位段的成员必须是intunsigned或者signed int再或者是char2.位段的空间是按照需要以4个字节或者1个字节的方式来开辟3.位段涉及了很多不确定因素位段是不跨平台的注重可移植的程序应该避免使用位段struct S { char a : 3; char b : 4; char c : 5; }; struct S s { 0 }; s.a 10; s.b 12; s.c 4;4.3位段的跨平台问题1.int 位段被当成有符号还是无符号是不确定的2.位段的最大的数目不能确定16位机器最大是1632位最大是323。位段中的成员在内存中从左向右还是从右向左是不确定的4.当一个结构包含俩个位段第二个位段成员比较大无法容纳于第一个剩余位置时是舍弃还是利用不确定总结跟结构相比位段可以达到同样的效果并且可以节省空间就是存在跨平台风险4.4位段的应用4.5位段的使用注意事项位段的几个成员共用一个字节这样有的成员没有起始位置这些位置处是没有地址的。所以不能对位段成员使用操作符可以先输入放在一个变量中然后赋值给位段的成员struct S { char a : 3; char b : 4; char c : 5; }; int main() { struct S a { 0 }; int b 0; scanf(%d, b); a.b b; printf(%d , a.b); return 0; }

更多文章