C 语言中同意将值为 0 的变量强制转换成任一类型的指针,转换结果是一个NULL指针。

  1. (type*)0 // 一个 type 类型的NULL指针

用这个指针訪问结构体内的成员是非法的,可是

  1. &(((type*)0)->field)

是为了计算 field 的地址 ,编译器不会产生訪问 field 的代码。仅仅会依据 type 的布局和起始地址在编译期计算这个地址(常量)。而又由于初始地址为 0,故该地址的值就是该结构体成员相对于结构体基址的偏移。

  1. (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.对齐后的长度必须是成员中最大的对齐參数的整数倍
  1. #include <iostream>
  2. using namespace std;
  3. #define ISUNSIGNED(x) ((x > 0) && (~x > 0))
  4. #define OffSet(type, field) ((size_t)&(((type*)0)->field))
  5. int main()
  6. {
  7. struct A{
  8. char a;
  9. int b;
  10. float c;
  11. double d;
  12. char e;
  13. union B{
  14. char f[100];
  15. struct C{
  16. int g[50];
  17. } h;
  18. }i;
  19. bool j;
  20. } s;
  21. cout << sizeof(A) << endl; // 232
  22. cout << "a 的起始偏移:"<< OffSet(A, a) << endl; // 0
  23. cout << "b 的起始偏移:"<< OffSet(A, b) << endl; // 4
  24. cout << "c 的起始偏移:"<< OffSet(A, c) << endl; // 8
  25. cout << "d 的起始偏移:"<< OffSet(A, d) << endl; // 16
  26. cout << "e 的起始偏移:"<< OffSet(A, e) << endl; // 24
  27. cout << "i 的起始偏移:"<< OffSet(A, i) << endl; // 28
  28. cout << "j 的起始偏移:"<< OffSet(A, j) << endl; // 228
  29. int p = 1;
  30. unsigned int q = 1;
  31. cout << p << " " << ~p << endl; // 1 -2
  32. cout << q << " " << ~q << endl; // 1 4294967294
  33. cout << "p是否是无符号数:" << ISUNSIGNED(p) << endl; // 0
  34. cout << "q是否是无符号数:" << ISUNSIGNED(q) << endl; // 1
  35. return 0;
  36. }

以上结构体分析:

  1. struct A{
  2. char a;
  3. int b;
  4. float c;
  5. double d;
  6. char e;
  7. union B{
  8. char f[100];
  9. struct C{
  10. int g[50];
  11. } h;
  12. }i;
  13. bool j;
  14. } 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 的倍数)

一个成员在内存中补位所占的内存,决定于该成员之后的成员类型。

參考:《程序猿笔试面试宝典》

怎样求结构体成员的偏移地址 || 结构体的 sizeof 总结的更多相关文章

  1. 套接字编程简介: IPV4套接字地址结构/ 通用套接字地址结构/ IPV6套接字地址结构/新通用套接字地址结构

    IPv4套接字地址结构通常也称为“网际套接字地址结构”,它以sockaddr_in命名,定义在<netinet/in.h>头文件中. struct in_addr { in_addr_t ...

  2. C语言根据结构体成员变量的地址,得到结构体的地址

    看nginx代码时发现双链表使用的是这种方法,记录一下 给出一个实例来说明 struct father_t {    int a;    char *b;    double c;}f;char *p ...

  3. 指针直接赋值为整型AND利用宏定义求结构体成员偏移量

    首先我们要更正一个很熟悉的概念,那就是指针不仅仅是“地址”,指针还有一个很重要的特性,那就是“类型”. 指针初始化时,“=”的右操作数; 除外,该语句表示指针为空): 所以 ; 这样的代码是不允许的. ...

  4. 由结构体成员地址计算结构体地址——list_entry()原理详解

    #define list_entry(ptr, type, member) container_of(ptr, type, member) 在进行编程的时候,我们经常在知道结构体地址的情况下,寻找其中 ...

  5. Linux中的两个经典宏定义:获取结构体成员地址,根据成员地址获得结构体地址;Linux中双向链表的经典实现。

    倘若你查看过Linux Kernel的源码,那么你对 offsetof 和 container_of 这两个宏应该不陌生.这两个宏最初是极客写出的,后来在Linux内核中被推广使用. 1. offse ...

  6. 【C语言】这种求结构体成员大小的方法,你可能需要了解一下~

    在C语言编程中,有时候需要知道某结构体中某成员的大小,比如使用堆内存来存储结构体中的某成员时,需要知道该成员的大小,才好确定所需申请的空间大小.求某结构体中某成员的大小,你会怎么做? 例子: type ...

  7. C/C++ 结构体成员在内存中的对齐规则(转载)

    这几天在看王艳平的<windows 程序设计>,第5章讲解了MFC框架是怎么管理窗口句柄到窗口实例之间的映射,用到了两个类CPlex和CMapPtrToPtr,用于管理内存分配的类(避免因 ...

  8. C/C++ 结构体成员在内存中的对齐规则

    这几天在看王艳平的<windows 程序设计>,第5章讲解了MFC框架是怎么管理窗口句柄到窗口实例之间的映射,用到了两个类CPlex和CMapPtrToPtr,用于管理内存分配的类(避免因 ...

  9. 【PE结构】由浅入深PE基础学习-菜鸟手动查询导出表、相对虚拟地址(RVA)与文件偏移地址转换(FOA)

    0 前言 此篇文章想写如何通过工具手查导出表.PE文件代码编程过程中的原理.文笔不是很好,内容也是查阅了很多的资料后整合出来的.希望借此加深对PE文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...

随机推荐

  1. shell-code-5-函数

    # 函数必须在使用前定义 # 如果不写return,将以最后一条命令运行结果,作为返回值. return后跟数值n(0-255) myFistFunc(){ read a read b return ...

  2. map函数的应用:UVa156-Ananagrams

    Ananagrams Most crossword puzzle fans are used to anagrams - groups of words with the same letters i ...

  3. 爬虫cookie

    Cookie Cookie 是指某些网站服务器为了辨别用户身份和进行Session跟踪,而储存在用户浏览器上的文本文件,Cookie可以保持登录信息到用户下次与服务器的会话. Cookie原理 HTT ...

  4. http协议工作原理(转)

     WWW是以Internet作为传输媒介的一个应用系统,WWW网上最基本的传输单位是Web网页.WWW的工作基于客户机/服务器计算模型,由Web 浏览器(客户机)和Web服务器(服务器)构成,两者之间 ...

  5. Flutter 发布APK时,release版本和debug版本的默认权限不同

    Flutter 发布APK时,release版本和debug版本的默认权限不同 @author ixenos 在调试模式下,默认情况下启用服务扩展和多个权限(在flutter中) 当您处于发布模式时, ...

  6. iOS学习笔记18-CoreData

    一.CoreData介绍 CoreData是iOS5之后新出来的的一个框架, 是对SQLite进行一层封装升级后的一种数据持久化方式.它提供了对象<-->关系映射的功能,即能够将OC对象转 ...

  7. iOS学习笔记07-运动事件和远程控制

    之前我们已经学习了触摸处理和手势识别,其实这两个同属于iOS事件的触摸事件,今天我们来学习下iOS事件的另外两个事件: 一.运动事件 运动事件,是通过加速器进行触发,和触摸事件一样,继承UIRespo ...

  8. URAL Formula 1 ——插头DP

    [题目分析] 一直听说这是插头DP入门题目. 难到爆炸. 写了2h,各种大常数,ural垫底. [代码] #include <cstdio> #include <cstring> ...

  9. [POJ2778]DNA Sequence(AC自动机 + DP + 矩阵优化)

    传送门 AC自动机加DP就不说了 注意到 m <= 10,所以模式串很少. 而 n 很大就需要 log 的算法,很容易想到矩阵. 但是该怎么构建? 还是矩阵 A(i,j) = ∑A(i,k) * ...

  10. 洛谷P2522 - [HAOI2011]Problem b

    Portal Description 进行\(T(T\leq10^5)\)次询问,每次给出\(x_1,x_2,y_1,y_2\)和\(d\)(均不超过\(10^5\)),求\(\sum_{i=x_1} ...