如何解决C语言中的uintptr_t和intptr_t
在研究XOR链表时,我遇到了一种名为intptr_t
/ uintptr_t
的类型,我知道我们可以将指针转换为该类型并将其作为整数操作而没有问题,但是
如果
我们确实有一个变量int a
(假设我们假设其地址为100),
这行(int* x=(intptr_t)100
表示x
指向a
吗?如果没有,那怎么办?
谢谢。
解决方法
int* x=(intptr_t)100
只是胡说八道,它不是有效的C语言,而是编译器必须抱怨的约束违反。有关详细信息,请参见"Pointer from integer/integer from pointer without a cast" issues。
也许您是说int* x=(intptr_t*)100
?在这种情况下,这是无效的指针转换-也不允许。
将100
转换为intptr
是没有意义的,因为100
已经是整数。当您有指针并需要一个表示该指针中存储的地址的整数时,可以使用intptr
。
如果您希望基于其绝对地址访问硬件寄存器或存储器位置,则这里有详细的指南:How to access a hardware register from firmware? 。
, XOR链表方法是一种用于构建链表的技巧,该链表可以使用单个指针的空间在两个方向上进行导航。诀窍是将下一个和上一个项目的地址的XOR存储在link
成员中,将这些地址转换为uintptr_t
(或intptr_t
)值,以按位互斥或对整数执行大小合适,并将此信息存储为整数:
struct item {
uintptr_t link;
int data; // item payload. Can be any number of members of any type
};
只要您知道上一个(或下一个)项目的地址,就可以双向遍历列表:
struct item *get_link(struct item *p,const struct item *previous) {
return (struct item *)(p->link ^ (uintptr_t)previous);
}
为避免在对准问题上发出警告,您可能需要添加以下附加演员表:
return (struct item *)(void *)(p->link ^ (uintptr_t)previous);
uintptr_t
是一个整数类型,被指定为与void *
具有相同的大小,因此可以包含来自任何数据指针的所有信息。将数据指针转换为uintptr_t
并通过强制转换返回应该产生相同的指针。
intptr_t
是相应的带符号类型,本质上用处不大。
XOR链接列表 hack如今在历史上尤为重要。唯一的优点是节省了体积,几乎不值得增加复杂性。如果需要双向扫描列表,则最好使用常规的双向链接列表。使用这种技巧进行扫描需要在遍历方向上将指向当前项目的指针和指向先前项目的指针保持不变,而常规的双向链表可以使用单个指针进行处理,因此可以以更简单的方式进行操作和/或共享
这是一个示例实现:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
struct item {
uintptr_t link;
int data; // item payload. Can be any number of members of any type
};
struct xor_list {
struct item *head;
struct item *tail;
};
struct item *get_link(struct item *ip,const struct item *previous) {
return (struct item *)(ip->link ^ (uintptr_t)previous);
}
struct item *get_next(struct item *ip,struct item **previous) {
struct item *next = get_link(ip,*previous);
*previous = ip;
return next;
}
uintptr_t make_link(struct item *prev,const struct item *next) {
return (uintptr_t)prev ^ (uintptr_t)next;
}
struct item *add_item(struct xor_list *lp,int data) {
struct item *ip = malloc(sizeof(*ip));
if (ip) {
struct item *tail = lp->tail;
ip->data = data;
if (tail) {
struct item *prev = get_link(lp->tail,NULL);
ip->link = make_link(tail,NULL);
tail->link = make_link(prev,ip);
lp->tail = ip;
} else {
ip->link = make_link(NULL,NULL);
lp->head = lp->tail = ip;
}
}
return ip;
}
int main() {
struct xor_list list = { NULL,NULL };
struct item *ip,*prev;
add_item(&list,1);
add_item(&list,2);
add_item(&list,3);
add_item(&list,4);
add_item(&list,5);
printf("traversing from head to tail:");
for (prev = NULL,ip = list.head; ip; ip = get_next(ip,&prev)) {
printf(" %d",ip->data);
}
printf("\n");
printf("traversing from tail to head:");
for (prev = NULL,ip = list.tail; ip; ip = get_next(ip,ip->data);
}
printf("\n");
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。