在C中存储整数和通用指针的最便携方式是什么?

时间:2015-03-30 10:36:02

标签: c pointers struct void-pointers flexible-array-member

我正在开发一个系统(虚拟机?不知道如何调用它),其中每个数据结构都是一个数组(或结构),在开头有三个整数字段(必须在一个接一个的开头,没有填充bytes)和 n 通用指针。我对此有很多想法,但似乎很难找到一个明确的解决方案。

以下是我的第一次尝试。

void **a = malloc(SOME_SIZE);
a[0] = (void *)1;
a[1] = (void *)0;
a[2] = (void *)1;
a[3] = malloc(SOME_SIZE); a[4] = malloc(SOME_SIZE); //and so on...

我在这里不确定void *对整数的投射是否安全。经过一番研究后,我按如下方式更改了代码。

void **a = malloc(SOME_SIZE);
*(uintptr_t *)a = 1;
*((uintptr_t *)a + 1) = 0;
*((uintptr_t *)a + 2) = 1;
a[3] = malloc(SOME_SIZE); a[4] = malloc(SOME_SIZE); //and so on...

但后来我发现在某些平台上sizeof(void *)可能不等于sizeof(uintptr_t)。所以我决定把它改成一个结构。

typedef struct data {
    size_t counts[3]; //padding bytes are okay after this line
    void *members[]; //flexible array member
} *data;

data a = malloc(sizeof(*a) + SOME_SIZE);
a->counts[0] = 1;
a->counts[1] = 0;
a->counts[2] = 1;
a->members[0] = malloc(SOME_SIZE); a->members[1] = malloc(SOME_SIZE); //and so on...

在这里我发现了一个问题,即C中没有100%可移植的通用指针,但我找不到解决方案,所以让我忽略一些不同指针大小的奇怪平台。

所以假设void *可以存储指向任何对象的指针,那么我的最后一个解决方案是否满足了我的目的?我对弹性阵列成员并不熟悉,所以我可能犯了一个错误。或者可能还有一点我错过了。

任何帮助表示感谢。

2 个答案:

答案 0 :(得分:2)

您可以使用void*的单个数组,将其转换为uintptr_t以获取其整数值。

uintptr_t是一个能够存储指针的无符号整数类型。 请参阅What is uintptr_t data type

请记住,这是一个非常丑陋,难以理解和危险的伎俩。

答案 1 :(得分:1)

假设你有一些方法可以知道哪些是整数,哪些是指针,你可以合法地使用union组合整数和指针。在所讨论的整数类型没有填充位或陷阱表示的系统上,存储指针然后读回整数应该总是产生一个值(而不是引起未定义的行为)但是应该考虑所讨论的整数的值无意义的。即使整数类型碰巧是uintptr_t,我也不认为类型惩罚是在指针类型和整数类型之间进行转换的合法方法。

存储整数值然后读取指针肯定是未定义整数值的行为不是通过读取合法指针可能读取的行为。如果有一个uintptr_t是通过打字合法指针获得的,使用类型punning将该值转换回指针可能会有效,但我不知道它是否已指定。我不希望将这样的整数转换为指针类型也行,也不会在通过强制转换获得的uintptr_t上使用类型双关语。