厦门网站建设的公司哪家好,公司网站怎么做,wordpress软件特点,百度搜索推广怎么做目录
结构体类型的声明
匿名结构体
全局结构体变量
嵌套结构体
访问结构体成员
结构的自引用
结构体变量的定义和初始化
结构体内存对齐
结构体内存对齐规则
修改默认对齐数 #pragma pack(n)
offsetof 求结构体成员相对于结构体开头的偏移量的宏。
为什么存在内存…目录
结构体类型的声明
匿名结构体
全局结构体变量
嵌套结构体
访问结构体成员
结构的自引用
结构体变量的定义和初始化
结构体内存对齐
结构体内存对齐规则
修改默认对齐数 #pragma pack(n)
offsetof 求结构体成员相对于结构体开头的偏移量的宏。
为什么存在内存对齐?
结构体传参
结构体实现位段位段的填充可移植性
什么是位段
位段的内存分配规则
位段的跨平台问题
位段的应用 结构体类型的声明
匿名结构体
/* 匿名结构体类型——只能用一次即在声明的时候顺带创建一个变量 */
struct
{char name[20];int age;
} s4;
全局结构体变量
struct Stu
{char name[20];int age;
} s1, s2; // s1 s2是全局变量struct Stu
{char name[20];int age;
} s1 {zhanghai, 22}; // 声明并初始化全局变量s1嵌套结构体
struct Score
{int score;char str[20];
};struct Stu
{char name[20];int age;struct Score s;
};int main()
{// 初始化局部变量s3struct Stu s3 {zhanghai, 22, {100, q}};printf(%s %d %d %s, s3.name, s3.age, s3.s.score, s3.s.str); // zhanghai 22 100 qreturn 0;
}
访问结构体成员
#include stdio.h/* 本例论如何声明结构体并使用三种方式访问结构体各成员 */struct MyType
{/* 成员 */char name[20];int age;char sex[10];char tele[12];
};/* 接受结构体指针地址struct MyType 类型int表示一种类型; *p是因为要指针赋值给指针变量时需加* */
void myPrintf(struct MyType *p)
{/* *p 表示使用*将指针变量p解引用得到 *p obj可参考09_pointer */printf(%s %d %s %s\n, (*p).name, (*p).age, (*p).sex, (*p).tele); // zhanghai, 20, nan, 15556201597/* p 表示指针变量结构体指针变量 - 成员名也就是结构体指针变量若想访问成员需要操作符 - */printf(%s %d %s %s\n, p-name, p-age, p-sex, p-tele); // zhanghai, 20, nan, 15556201597
}int main()
{struct MyType obj {zhanghai, 20, nan, 15556201597};// 结构体对象.成员名printf(%s %d %s %s\n, obj.name, obj.age, obj.sex, obj.tele); // zhanghai, 20, nan, 15556201597// 将结构体指针传入myPrintf(obj);return 0;
}
结构的自引用 struct Node
{int data;struct Node* next;
}; typedef struct Node
{int data;struct Node* next;
}Node; 结构体变量的定义和初始化
struct Point
{int x;int y;
} p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2//初始化定义变量的同时赋初值。
struct Point p3 {x, y};
struct Stu //类型声明
{char name[15];//名字int age; //年龄
};
struct Stu s {zhangsan, 20};//初始化
struct Node
{int data;struct Point p;struct Node* next;
} n1 {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 {20, {5, 6}, NULL};//结构体嵌套初始化
结构体内存对齐
结构体内存对齐规则 1. 第一个成员在与结构体变量偏移量为0的地址处。 2. 其他成员变量要对齐到某个数字对齐数的整数倍的地址处。 对齐数 编译器默认的一个对齐数 与 该成员大小的较小值。gcc没有编译器对齐数对齐数就是成员自身大小 3. 结构体总大小为最大对齐数每个成员变量都有一个对齐数的整数倍。 4. 如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。 struct S1
{char c1;int i;char c2;
};struct S2
{char c1;char c2;int i;
};struct S3
{double d;char c;int i;
};printf(%d\n, sizeof(struct S1)); // 12
printf(%d\n, sizeof(struct S2)); // 8
printf(%d\n, sizeof(struct S3)); // 16
修改默认对齐数 #pragma pack(n)
/* 修改编译器默认对齐数为4请看结构体规则第2点 */
#pragma pack(4)
struct S
{int i; // 0double d; // 4 8 —— 4
};
#pragma pack()#pragma pack(1)
struct Sd
{char c;int i;char c1;
};
#pragma pack()printf(%d\n, sizeof(struct S)); // 12 修改对齐数之前是16
printf(%d\n, sizeof(struct Sd)); // 6
offsetof 求结构体成员相对于结构体开头的偏移量的宏。 struct S1
{char c1;int i;char c2;
};struct S3
{double d;char c;int i;
};// S1
printf(%d\n, offsetof(struct S1, c1)); // 0
printf(%d\n, offsetof(struct S1, i)); // 4
printf(%d\n, offsetof(struct S1, c2)); // 8
// s3
printf(%d\n, offsetof(struct S3, d)); // 0
printf(%d\n, offsetof(struct S3, c)); // 8
printf(%d\n, offsetof(struct S3, i)); // 12
结构在对齐方式不合适的时候我们可以自己更改默认对齐数。
为什么存在内存对齐? 1. 平台原因(移植原因) 不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在某些地址处取某些特定类型的数据否则抛出硬件异常。 2. 性能原因 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于为了访问未对齐的内存处理器需要作两次内存访问而对齐的内存访问仅需要一次访问。 总体来说 结构体的内存对齐是拿空间来换取时间的做法 结构体传参 函数传参的时候参数是需要压栈会有时间和空间上的系统开销。如果传递一个结构体对象的时候结构体过大参数压栈的的系统开销比较大所以会导致性能的下降。
/* 结构体传参 */
struct SC
{int data[1000];int num;
};// 结构体传参
void print1(struct SC s)
{printf(%d\n, s.num);
}
// 结构体地址传参
void print2(struct SC *ps)
{printf(%d\n, ps-num);
}struct SC s {{1, 2, 3, 4}, 1000};
print1(s); // 传结构体
print2(s); // 传地址
结构体实现位段位段的填充可移植性
什么是位段 位段的声明和结构是类似的有两个不同 位段的成员必须是 int、unsigned int 或signed int 。 位段的成员名后边有一个冒号和一个数字。 struct A
{int _a : 2; int _b : 5;int _c : 10; int _d : 30;
}; A就是一个位段类型。
位段的内存分配规则 1. 位段的成员可以是 int unsigned int signed int 或者是 char 属于整形家族类型 2. 位段的空间上是按照需要以4个字节 int 或者1个字节 char 的方式来开辟的。 3. 位段涉及很多不确定因素位段是不跨平台的注重可移植的程序应该避免使用位段。 4. int 位段被当成有符号数还是无符号数是不确定的。 5. 位段中最大位的数目不能确定。16位机器最大1632位机器最大32写成27在16位机器会出问题。 6. 位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义。 7. 当一个结构包含两个位段第二个位段成员比较大无法容纳于第一个位段剩余的位时是舍弃剩余的位还是利用这是不确定的 struct A
{/* 上来二话不说先开辟4个字节空间也就是 32个bit位 */int _a : 2; // _a占2个bit位int _b : 5; // _b占5个bit位int _c : 10; // _c占10个bit位/* 到这里发现 只剩 15 个bit位不够存放_d的30个bit那么会再次开辟4个字节用来存放 */int _d : 30; // _d占30个bit位
};printf(%d\n, sizeof(struct A)); // 8 未使用位段就是16个字节
位段的跨平台问题 int 位段被当成有符号数还是无符号数是不确定的。位段中最大位的数目不能确定。16位机器最大1632位机器最大32写成27在16位机器会出问题。位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义。当一个结构包含两个位段第二个位段成员比较大无法容纳于第一个位段剩余的位时是舍弃剩余的位还是利用这是不确定的
总结跟结构相比位段可以达到同样的效果并且可以很好的节省空间但是有跨平台的问题存在
位段的应用