示例:

typedef struct  _user {char name[20];char sex[20];int age;struct list_head mylist;//自定义结构体里保存双向循环链表头结点
}user;

如果知道mylist的地址,如何获取user的地址呢?

可以这样:

u = (user*)((int)pos1 - sizeof(user) + sizeof((((user*)0)->mylist)));

使用mylist的地址pos1,减去user与mylist的容量大小之差,再将结果转换回user*类型,最后得到的就是user u的地址

注意:对指针直接加减,是相对于这个指针它自身的类型的,要把指针地址转换成实际数值再相加减

(user*)0用法可参考:C语言如何获取结构体中指定元素的大小?sizeof ( (X*)0 ) -> Y)

ffffff

但是不得不考虑到可能存在对齐的情况,就是空间与实际存储的数据大小不一致的情况,可见:C语言 如何计算结构体的大小

比如这里就发生了地址对齐:

char sex之后age之前空出了两个字节的存储空间,以满足后面int类型大小的倍数,但是因为在mylist之后就没发生过字节对齐的情况,(mylist存放的是prev* 和next*两个指针),所以对结果不影响

但是如果mylist之后还存在特殊情况,用上面的方法还能计算出mylist和user真实的地址差吗??

我们再来做个小测试:

&((user*)0)->mylist;
&(((user*)0)->mylist);
(int)&((user*)0)->mylist;


这个语法,实际上就是offsetof函数,但是我用不了这个函数不知道咋回事,直接把它源码弄来!

可以看到,->是比&优先级高的,所以不用加括号()

offsetof()函数是啥,可以看这:C语言中 offsetof 的使用

这个函数可以求得结构体中元素(头)相对于结构体(头)的地址差!

所以我们想要通过元素(头)地址求结构体(头)地址,只要这样即可:

u = (user*)((int)pos1 - (int)&((user*)0)->mylist);

是不是又比我们开头那会用的又简单了很多???!!!

参考文章:C语言如何获取结构体中指定元素的大小?sizeof ( (X*)0 ) -> Y)

完整泛型链表代码:by jianggong

main.c不是main.cpp!!

#include <stdio.h>
struct list_head {struct list_head* next;struct list_head* prev;
};#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)//根据structd的成员获取struct的地址
#define container_of(ptr, type, member) ((type *)(((char *)ptr) - (int)(&(((type*)0)->member))))//链表遍历#define list_for_each(pos, head) \for (pos = (head)->next; pos != (head); pos = pos->next)#define list_for_each_prev(pos, head) \for (pos = (head)->prev; pos != (head); pos = pos->prev)#define LIST_HEAD_INIT(name) { &(name), &(name) }#define LIST_HEAD(name) \struct list_head name = LIST_HEAD_INIT(name)static inline void __list_add(struct list_head* new_,struct list_head* prev,struct list_head* next)
{next->prev = new_;new_->next = next;new_->prev = prev;prev->next = new_;
}static inline void list_add(struct list_head* new_, struct list_head* head)
{__list_add(new_, head, head->next);
}static inline void list_add_tail(struct list_head* new_, struct list_head* head)
{__list_add(new_, head->prev, head);
}static inline void __list_del(struct list_head* prev, struct list_head* next)
{next->prev = prev;prev->next = next;
}static inline void list_del(struct list_head* entry)
{__list_del(entry->prev, entry->next);
}typedef struct  _user {char name[11];char sex[11];int age;struct list_head mylist;//自定义结构体里保存双向循环链表头结点
}user;typedef struct  _records {char name[20];int type;struct list_head mylist;//自定义结构体里保存双向循环链表头结点
}records;int main()
{//LIST_HEAD(header_task);//初始化头结点struct list_head header_task1 = { &(header_task1), &(header_task1) };struct list_head header_task2 = { &(header_task2), &(header_task2) };user u1 = { "张麻子", "男", 40 };user u2 = { "牛魔王", "男", 36 };user u3 = { "蜘蛛精", "女", 28 };records r1 = {"张麻子", 1};records r2 = {"蜘蛛精", 2};records r3 = {"牛魔王", 1};//新建struct list_head* pos1;struct list_head* pos2;user* u;records* r;//头插法list_add(&u1.mylist, &header_task1);list_add(&u2.mylist, &header_task1);list_add(&u3.mylist, &header_task1);list_add(&r1.mylist, &header_task2);list_add(&r2.mylist, &header_task2);list_add(&r3.mylist, &header_task2);//list_for_each(pos1, &header_task1) {//    u = container_of(pos1, user, mylist);//    printf("data is %d\n", u->age);//}for (pos1 = (&header_task1)->next; pos1 != (&header_task1); pos1 = pos1->next){//u = container_of(pos1, user, mylist);//u = ((user*)(((char*)pos1) - (int)(&(((user*)0)->mylist))));//u = (user*)((int)pos1 - sizeof(user) + sizeof((((user*)0)->mylist)));//&((user*)0)->mylist;//->优先级高于&u = (user*)((int)pos1 - (int)&((user*)0)->mylist);printf("data is %d\n", u->age);}printf("----------\n");list_del(&u2.mylist);list_for_each(pos1, &header_task1) {u = container_of(pos1, user, mylist);printf("data is %d\n", u->age);}printf("Hello World!\n");return 0;
}

运行结果:

data is 28
data is 36
data is 40
----------
data is 28
data is 40
Hello World!

C语言 泛型链表 如何计算(结构体中各元素)相对内存地址?(字节对齐,结构体对齐)offsetof()函数 ( (struct X*)0 ) -> Y)语法(匿名结构体)相关推荐

  1. C语言如何获取结构体中指定元素的大小?sizeof ( (X*)0 ) -> Y)(空指针操作)

    获取结构体的大小,这好办,这样就可以了: #include <stdio.h>struct user {char name[20];char age[10]; };int main() { ...

  2. C语言试题三十七之求除一个2×m整型二维数组中最大元素的值,并将此值返回调用函数。

    1. 题目 请编写一个函数function,它的功能是:求除一个2×m整型二维数组中最大元素的值,并将此值返回调用函数. 2 .温馨提示 C语言试题汇总里可用于计算机二级C语言笔试.机试.研究生复试中 ...

  3. Cheat Enginee(CE)对扫雷中部分属性的内存地址寻找以及修改~逆向分析

    Cheat Enginee(CE)对扫雷中部分属性的内存地址寻找以及修改 分析"初级"."中级"和"高级"的棋盘内存地址范围 "初 ...

  4. C语言 泛型链表的实现

    参考文章:使用C语言实现"泛型"链表 文章目录 jiang工给的泛型链表例子,有点看不怎么懂,自己写个看看: 实现方法 方法1:链表指针指向整个结点,结点中存放指向数据的指针 方法 ...

  5. c语言链表错误,C语言创建链表错误之通过指针参数申请动态内存实例分析

    本文实例讲述了C语言创建链表中经典错误的通过指针参数申请动态内存,分享给大家供大家参考之用.具体实例如下: #include #include // 用malloc要包含这个头文件 typedef s ...

  6. 【C 语言】变量本质 ( 变量修改 | 直接修改变量 | 通过内存地址间接修改变量 | 通过指针间接修改变量 )

    文章目录 一.变量修改 1.直接修改变量 2.通过内存地址间接修改变量 3.通过指针间接修改变量 一.变量修改 访问 变量 , 就是 访问 内存空间 ; 访问 指的是 读写 内存 ; 修改变量的方式 ...

  7. python内置函数返回序列中最大元素_Python之路(第八篇)Python内置函数、zip()、max()、min()...

    一.python内置函数 abs() 求绝对值 例子 print(abs(-2)) all() 把序列中每一个元素做布尔运算,如果全部都是true,就返回true, 但是如果是空字符串.空列表也返回t ...

  8. python查看内存地址的内容_python中如何查看指定内存地址的内容

    python中一般并不需要查看内存内容,但作为从C/C++过来的人,有的时候还是想看看内存,有时是为了验证内容是否与预期一致,有时是为了探究下内存布局. from sys import getsize ...

  9. Visual Studio 2019中查看变量的内存地址

    Visual Studio 2019中查看变量内存地址 变量所在行打断点 执行程序 打开内存显示窗口 输入取 &a 获得a的地址值 点击a的地址值拖动至内存显示窗口中,此时第一行显示的为变量 ...

最新文章

  1. SpringMVC传递multiple类型select后台Controller的接收方法
  2. 红外摄像机镜头的技术知识大全
  3. Database之SQLSever:SQL命令实现四则运算、desc降序、like模糊查询、distinct去重、MAX/MIN/SUM/AVG/COUNT/GROUP/having等案例之详细攻略
  4. 部署 Job (第四部分)
  5. windows10彻底杀死卡死的顽固进程
  6. P2272 [ZJOI2007]最大半连通子图
  7. 定时器_定时器设计的门铃
  8. linux开源视频监控软件,Linux开源智能视频监控软件zoneminder的安装
  9. 企业级大数据架构设计及规划方案.ppt
  10. div水平垂直居中的常用方法
  11. java对excel插入水印_Java通过POI和JXL给Excel动态添加水印
  12. 马云:阿里巴巴要培养更多的京东并让这些企业挣钱
  13. 曙光服务器怎么外接显示器,iPad平板外接显示器教程 | iPad平板怎么外接显示器_什么值得买...
  14. Galahad(板子:区间不重复数字的和,树状数组/线段树)
  15. 上岸美团,我为何放弃算法转开发
  16. steam在matlab是什么,什么是STEAM,和STEM有何区别?
  17. 电视2k和4k有什么区别
  18. ASP.NET中使用网络驱动器
  19. vue创建项目报错command not found:create-webpack
  20. html上传文件框架,文件上传 - FastAdmin框架文档 - FastAdmin开发文档

热门文章

  1. ArcGIS时态数据应用——动态展示3个月内犯罪案件数量变化
  2. 探测 Lombok 工具
  3. python爬虫知识_Python 爬虫技术分享
  4. 【PM模块】维护处理简介
  5. 批量显示JOB Log
  6. SM04 在线用户管理(踢人事务)
  7. ALEIDoc EDI(1)--OverView
  8. 如何用SAP编制现金流量表
  9. 百度健康打通医药电商服务
  10. svn如何隐藏代码路径_程序员课堂—如何通过改善代码风格来消灭隐藏bug