1

我一直在思考。我还没有找到任何直接回答这个问题的东西,但我想我知道答案;我只是想从一些更有经验的人那里得到一些意见。

已知:

一个 void 指针只指向一个内存地址。它不包括类型信息。

int 指针指向包含 int 的内存地址。它将读取指向整数的内存地址中的任何内容,而不管最初填充到地址中的是什么。

问题:

如果 void 双指针指向void ** foo动态分配的 void 指针数组

void ** foo = malloc(sizeof(void *) * NUM_ELEMENTS);

是不是真的,正如我所假设的那样,由于 void 指针的独特性质,实际上缺乏任何类型的类型信息,而不是void ** foo等效的语句

void * bar = malloc(sizeof(void *) * NUM_ELEMENTS);

并且当我通过分配特定类型来使用间接访问时,例如

(有人指出我不能取消引用 void 指针。为了清楚问题的目的,下一行更改为适合该信息)

int ** fubar = bar;

我会从单个void 指针中得到一个适当的指针,它就像一个双精度的指针吗?

还是这一切都在我的脑海中?

4

2 回答 2

3

It is permissible to assign the result of malloc to a void * object and then later assign it to an int ** object. This is because the return value of malloc has type void * anyway, and it is guaranteed to be suitable for assignment a pointer to any type of object with a fundamental alignment requirement.

However, this code:

#define NUM_ELEMENTS 1000
void *bar = malloc(sizeof(void *) * NUM_ELEMENTS);
int **fubar = bar;
*fubar = 0;

is not guaranteed by the C standard to work; it may have undefined behavior. The reason for this is not obvious. The C standard does not require different types of pointers to have the same size. A C implementation may set the size of an int * to one million bytes and the size of a void * to four bytes. In this case, the space allocated for 1000 void * would not be enough to hold one int *, so the assignment to *fubar has undefined behavior. Generally, one would implement C in such a way only to prove a point. However, similar errors are possible on a smaller scale: There are C implementations in which pointers of different types have different sizes.

A pointer to an object type may be converted to a pointer to another object type provided the pointer has alignment suitable for the destination type. If it does, then converting it back yields a pointer with the original value. Thus, you may convert pointers to void * to pointers to void and back, and you may convert pointers to void * to pointers to int * and back, provided the alignments are suitable (which they will be if the pointers were returned by malloc and you are not using custom objects with extended alignments).

In general, you cannot write using a pointer to an object type and then read the same bytes using a pointer to a different object type. This violates aliasing rules. An exception is that if one of the pointers is to a character type. Also, many C implementations do support such aliasing, but it may require setting command-line options to enable such support.

This prohibition on aliasing includes reinterpreting pointers. Consider this code:

int a;
int *b = &a;
void **c = (void **) &b;
void *d = *c;
int *e = (int *) d;

In the fourth line, c points to the bytes that b occupies but *c tries to interpret those bytes as a void *. This is not guaranteed to work, so the value that d gets is not necessarily a pointer to a, even when it is converted to int * as in the last line.

于 2013-12-02T21:56:36.430 回答
0

在 C 标准下,您提供的代码的行为是未定义的,因为您分配了一个void指针数组,然后尝试将其用作指针数组int。标准中没有任何内容要求这两种指针具有相同的大小或对齐方式。现在如果你说

void * bar = malloc(sizeof(int*) * NUM_ELEMENTS);
int ** fubar = bar;

那么一切都会好起来的。

现在在绝大多数机器上,anint*和 avoid* 实际上具有相同的大小和对齐方式。所以你的代码在实践中应该可以正常工作。

此外,这两个不等价:

void ** foo = malloc(sizeof(void *) * NUM_ELEMENTS);
void * bar = malloc(sizeof(void *) * NUM_ELEMENTS);

这是因为foo可以在任何元素处取消引用以获取 void 指针,而bar不能。例如,这个程序是正确的,00000000在我的 32 位机器上打印:

#include <stdio.h>
#include <stdlib.h>

int main(void) 
{
  void **a = calloc(10, sizeof(void*));
  printf("%p\n", a[0]);
  return 0;
}

另一点是您似乎认为类型信息在机器级别的指针中是明确的。这是不正确的(至少对于绝大多数实现而言)。C 指针的类型通常仅在程序编译时表示。到编译完成时,显式类型信息通常会丢失,除非在调试符号表中,这些符号表不是可运行的代码。(这有一些小的例外。对于 C++,情况非常不同。)

于 2013-12-02T21:52:54.697 回答