如何求结构体成员的偏移地址 || 结构体的 sizeof 总结
2015-08-12 16:22
323 查看
C 语言中允许将值为 0 的变量强制转换成任一类型的指针,转换结果是一个NULL指针;
用这个指针访问结构体内的成员是非法的,但是
是为了计算 field 的地址 ,编译器不会产生访问 field 的代码,只会根据 type 的布局和起始地址在编译期计算这个地址(常量)。而又因为初始地址为 0,故该地址的值就是该结构体成员相对于结构体基址的偏移。
结构体的 sizeof 的相关知识:
对 32 位操作系统,默认按 4 字节对齐;
sizeof(union),结果是 union 占用内存最大成员的大小(各成员共享内存)
编译器是按照什么样的原则进行对齐的?
1.数据类型自身的对齐值:
对于char型数据,其自身对齐值为1,对于short型为2,对于int, float类型,其自身对齐值为4,对于double类型其自身对齐值为8,单位字节。
2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
5.对齐后的长度必须是成员中最大的对齐参数的整数倍
以上结构体分析:
结构体 A 的自身对齐值为最大的成员的自身对齐值,为 8 (double d), 注意内部结构体 C 的最大对齐值是 4 (int),Union B 最大对齐值是 4 (int);
成员char a 的本身对齐值是 1,结构体对齐值是 8,按 1 字节对齐;
成员 int b 的 本身对齐值是 4,结构体对齐值是 8,按 4 字节对齐,它的起始偏移地址为 4;
成员 float c 的 本身对齐值是 4,结构体对齐值是 8,按 4 字节对齐,它的起始偏移地址为 8;
成员 double d 的 本身对齐值是 8,结构体对齐值是 8,按 8 字节对齐,它的起始偏移地址为 16;
成员 char e 的 本身对齐值是 1,结构体对齐值是 8,按 1 字节对齐,它的起始偏移地址为 24;(16+8)
成员 Union B i 的 本身对齐值是 4,结构体对齐值是 8,按 4 字节对齐,它的起始偏移地址为 28;
成员 bool j 的 本身对齐值是 1,结构体对齐值是 8,按 1 字节对齐,它的起始偏移地址为 228 ;(28+200)
结构体对齐值是 8, 因此结构体 A 的大小为 232 (228+1 补齐成 8 的倍数)
一个成员在内存中补位所占的内存,决定于该成员之后的成员类型。
参考:《程序员笔试面试宝典》
(type*)0 // 一个 type 类型的NULL指针
用这个指针访问结构体内的成员是非法的,但是
&(((type*)0)->field)
是为了计算 field 的地址 ,编译器不会产生访问 field 的代码,只会根据 type 的布局和起始地址在编译期计算这个地址(常量)。而又因为初始地址为 0,故该地址的值就是该结构体成员相对于结构体基址的偏移。
(size_t)&(((type*)0)->field)
结构体的 sizeof 的相关知识:
对 32 位操作系统,默认按 4 字节对齐;
sizeof(union),结果是 union 占用内存最大成员的大小(各成员共享内存)
编译器是按照什么样的原则进行对齐的?
1.数据类型自身的对齐值:
对于char型数据,其自身对齐值为1,对于short型为2,对于int, float类型,其自身对齐值为4,对于double类型其自身对齐值为8,单位字节。
2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
5.对齐后的长度必须是成员中最大的对齐参数的整数倍
#include <iostream> using namespace std; #define ISUNSIGNED(x) ((x > 0) && (~x > 0)) #define OffSet(type, field) ((size_t)&(((type*)0)->field)) int main() { struct A{ char a; int b; float c; double d; char e; union B{ char f[100]; struct C{ int g[50]; } h; }i; bool j; } s; cout << sizeof(A) << endl; // 232 cout << "a 的起始偏移:"<< OffSet(A, a) << endl; // 0 cout << "b 的起始偏移:"<< OffSet(A, b) << endl; // 4 cout << "c 的起始偏移:"<< OffSet(A, c) << endl; // 8 cout << "d 的起始偏移:"<< OffSet(A, d) << endl; // 16 cout << "e 的起始偏移:"<< OffSet(A, e) << endl; // 24 cout << "i 的起始偏移:"<< OffSet(A, i) << endl; // 28 cout << "j 的起始偏移:"<< OffSet(A, j) << endl; // 228 int p = 1; unsigned int q = 1; cout << p << " " << ~p << endl; // 1 -2 cout << q << " " << ~q << endl; // 1 4294967294 cout << "p是否是无符号数:" << ISUNSIGNED(p) << endl; // 0 cout << "q是否是无符号数:" << ISUNSIGNED(q) << endl; // 1 return 0; }
以上结构体分析:
struct A{ char a; int b; float c; double d; char e; union B{ char f[100]; struct C{ int g[50]; } h; }i; bool j; } s;
结构体 A 的自身对齐值为最大的成员的自身对齐值,为 8 (double d), 注意内部结构体 C 的最大对齐值是 4 (int),Union B 最大对齐值是 4 (int);
成员char a 的本身对齐值是 1,结构体对齐值是 8,按 1 字节对齐;
成员 int b 的 本身对齐值是 4,结构体对齐值是 8,按 4 字节对齐,它的起始偏移地址为 4;
成员 float c 的 本身对齐值是 4,结构体对齐值是 8,按 4 字节对齐,它的起始偏移地址为 8;
成员 double d 的 本身对齐值是 8,结构体对齐值是 8,按 8 字节对齐,它的起始偏移地址为 16;
成员 char e 的 本身对齐值是 1,结构体对齐值是 8,按 1 字节对齐,它的起始偏移地址为 24;(16+8)
成员 Union B i 的 本身对齐值是 4,结构体对齐值是 8,按 4 字节对齐,它的起始偏移地址为 28;
成员 bool j 的 本身对齐值是 1,结构体对齐值是 8,按 1 字节对齐,它的起始偏移地址为 228 ;(28+200)
结构体对齐值是 8, 因此结构体 A 的大小为 232 (228+1 补齐成 8 的倍数)
一个成员在内存中补位所占的内存,决定于该成员之后的成员类型。
参考:《程序员笔试面试宝典》
相关文章推荐
- linux c mysql 开发
- UNIX网络编程1 理解同步、阻塞、非阻塞、异步网络I/O
- 大约 C++ 几个方面分析--overload, override, overwrite, rewrite
- 算法回顾(三) 二分查找
- mongodba安装及配置windows
- Generate Parentheses
- JAVA并发编程
- 微信浏览器网页授权JS封装
- 220 Contains Duplicate III
- java邮件发送和短信发送(一)
- win7 下adb server is out of date. killing... 连接手机问题已解决
- android与js交互(二)
- 哈希表(散列表)
- 字符输入,输出问题
- C#中的泛型
- SQLite 日期 & 时间
- Linux系统排查4——网络篇
- C++/CLI托管
- 自定义GridView六宫格
- Java FileInputStream/FileOutputStream的应用 文件读取和写入