【问题标题】:What is the most portable way to store both integers and generic pointers in C?在 C 中存储整数和通用指针的最便携方式是什么?
【发布时间】:2015-03-30 10:36:02
【问题描述】:

我正在开发一个系统(虚拟机?不知道如何调用它),其中每个数据结构都是一个数组(或结构),开头有三个整数字段(必须紧接着一个没有填充的开头) 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 * 可以存储指向任何对象的指针,我的最后一个解决方案是否满足我的目的?我对灵活的数组成员不太熟悉,所以我可能犯了一个错误。或者我仍然可能遗漏了一些要点。

任何帮助表示赞赏。

【问题讨论】:

  • uintptr_t 可以满足其预期目的:您可以将任何 void 指针 转换为 并返回并获得相同的指针。没有人说你可以将uintptr_t 类型的任意值转换为void * 并得到有意义的东西。
  • 请记住,void **a 并不安全。请参阅C FAQ 4.9C 中没有通用的指针指向指针类型。void * 仅用作通用指针,因为在将其他指针类型分配给和从@987654334 分配时自动应用转换(如果需要) @s;
  • 为什么void** a 不安全?我不希望这样的指针可以指向除void* 之外的任何东西,并且可以安全地执行a[0] = &someInt;,然后执行*((int*)*a)=123;x=*((int*)*a);,即使不能安全地执行int **b; ... a=b;。当然,将任意int 值转换为指针是不好的。

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


【解决方案1】:

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

uintptr_t 是一种能够存储指针的无符号整数类型。 见What is uintptr_t data type

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

【讨论】:

  • 我在 C 规范中没有找到“与指针大小相同的整数类型”。 uintptr_t 不能大于指针类型吗?
  • @chux 可能是这样,但这有点奇怪......无论如何我用链接更新了我的答案。
【解决方案2】:

假设您有一些方法可以知道哪些是整数,哪些是指针,您可以合法地使用union,它结合了整数和指针。在相关整数类型没有填充位或陷阱表示的系统上,存储指针然后读回整数应始终产生一个值(而不是导致未定义行为),但应考虑相关整数的值无意义的。即使整数类型恰好是uintptr_t,我认为类型双关语不能保证是指针类型和整数类型之间转换的合法方式。

存储一个整数值然后读取指针肯定是未定义整数值的行为不是可以通过读取合法指针来读取的行为。如果有一个uintptr_t 是通过对合法指针进行类型双关获得的,那么使用类型双关将该值转换回指针可能会起作用,但我不知道它是否已指定。我不希望将这样一个整数转换为指针类型会起作用,也不希望对通过转换获得的uintptr_t 使用类型双关语。

【讨论】:

    猜你喜欢
    • 2020-07-23
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 2020-06-14
    • 1970-01-01
    • 2010-10-12
    相关资源
    最近更新 更多