C语言中的uintptr_t和intptr_t

uintptr_t and intptr_t in C language

当我在研究 XOR 链表时,我 运行 转换为一个名为 intptr_t/uintptr_t 的类型,我知道我们可以将指针转换为该类型并将其作为整数没有问题,但是 如果 我们确实有一个变量 int a(假设它的地址是 100), 这条线 (int* x=(intptr_t)100) 是否意味着 x 指向 a?如果不是,它会做什么?

提前致谢。

int* x=(intptr_t)100 只是胡说八道,它不是有效的 C,而是编译器必须抱怨的 约束违规 。有关详细信息,请参阅

也许你的意思是 int* x=(intptr_t*)100?在这种情况下,它是一个无效的指针转换——也是不允许的。

100 转换为 intptr 没有意义,因为 100 已经是一个整数。当您有一个 指针 并且需要一个表示存储在该指针中的地址的整数时,您可以使用 intptr

如果您希望根据绝对地址访问硬件寄存器或内存位置,那么这里有一个详细的指南:How to access a hardware register from firmware?

XOR 链表 方法是一种构建链表的技巧,可以使用 space 为单个指针在两个方向上导航。技巧是将下一项和上一项的地址异或存储在 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 今天主要是具有历史意义。唯一的优点是体积小,不值得增加复杂性。如果需要双向扫描列表,最好使用常规的双向链表。使用此技巧的扫描需要在遍历方向上保持指向当前项目和前一个项目的指针,而常规双向链表可以用单个指针处理,因此可以操纵 and/or 共享更简单的时尚。

这是一个示例实现:

#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, &prev)) {
        printf(" %d", ip->data);
    }
    printf("\n");
    return 0;
}