C语言 泛型链表 如何计算(结构体中各元素)相对内存地址?(字节对齐,结构体对齐)offsetof()函数 & ( (struct X*)0 ) -> Y)语法
Posted Dontla
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言 泛型链表 如何计算(结构体中各元素)相对内存地址?(字节对齐,结构体对齐)offsetof()函数 & ( (struct X*)0 ) -> Y)语法相关的知识,希望对你有一定的参考价值。
示例:
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)语法的主要内容,如果未能解决你的问题,请参考以下文章