C 将空指针强制转换为任意类型指针

C 将空指针强制转换为任意类型指针,c,void-pointers,C,Void Pointers,我正试图用C语言实现我自己的通用数据结构,这对我自己的学习有好处。我目前的工作是一个向量,我希望它能够容纳一个任意类型(或者至少是类型大小,但这不是C中真正重要的吗?)。我的结构如下: struct vector { void *item; size_t element_size; size_t num_elements; } 但是,我不明白的是,如果类型应该是任意的,我如何引用*项数组中的特定元素。我知道元素的大小,但这对索引引用(例如项[5])没有帮助,因为void

我正试图用C语言实现我自己的通用数据结构,这对我自己的学习有好处。我目前的工作是一个向量,我希望它能够容纳一个任意类型(或者至少是类型大小,但这不是C中真正重要的吗?)。我的结构如下:

struct vector
{
    void *item;
    size_t element_size;
    size_t num_elements;
}

但是,我不明白的是,如果类型应该是任意的,我如何引用*项数组中的特定元素。我知道元素的大小,但这对索引引用(例如项[5])没有帮助,因为void不是一种类型。我认为将元素称为字节偏移量是最容易的。因此,如果我持有一个大小为12的结构向量,那么项[5]将位于12*5=60字节处。然而,我不明白如何检索这些数据。我知道我想从item+60中得到12个字节,但我如何让编译器理解这一点呢?我正在进入预处理器领域吗?

对于任何对象指针类型来说,
void*
都是一种通用指针类型。为了正确地强制转换
void*
并取消对指针的引用,您必须知道它所指向的类型

下面是一个使用不同指针类型的
void*
对象的示例

void *p;
int a = 42, b;
double f = 3.14159, g;

p = &a;
b = *(int *) a;

p = &f;
g = *(double *) f; 
因此,如果我持有一个大小为12的结构向量,那么项[5]将位于12*5=60字节处。然而,我不明白如何检索这些数据。我知道我想从item+60中得到12个字节,但我如何让编译器理解这一点呢

假设您给定的类型是
foo
。正如您已经了解的,您需要到达
item+(5*12)
的地址,然后在将空指针转换为
foo*
后取消对空指针的引用

foo my_stuff = *(foo *)(item + 5 * 12);
如果可以在编译时确定数据的类型,也可以使用
sizeof()

foo my_stuff = *(foo *)(item + 5 * sizeof(foo));

sizeof
是以字符为单位的度量,因此您可以执行以下操作:

void *start_of_sixth_element = ((char*)item) + (5 * element_size);
知道每个元素的类型的人可以将第六个元素的
start\u转换为正确的类型来使用它

void*
在某种程度上是一个错误的选择,因为在标准C中不能使用
void*
指针进行指针运算(有一个GNU扩展允许它,但对于可移植代码,至少在算法中使用
char*
unsigned char*

在应用偏移量5之前知道正确类型的代码可以执行以下操作:

correct_type *sixth_element = ((correct_type *)item) + 5;
void不是一种类型


它是一种类型,只是不是一种“完整类型”。“不完整类型”几乎意味着编译器不知道
void*
真正指的是什么。

给定一个类型,有没有简单的方法来找出
元素大小的正确值?(我在考虑对齐要求。)@aix:给定类型,
element\u size
sizeof(type)
:对象的大小已经包括对齐所需的任何填充。对齐方式取决于
项所指向的内存是如何分配的。只要它被分配了
malloc(element\u size*num\u elements)
(并且乘法不会溢出!),那么就不存在对齐问题,因为
malloc
可以“保证”为任何对象返回对齐的内存。我使用snigger引号是因为SIMD指令的超大类型通常被实现排除在外。@aix中,
sizeof
运算符考虑对齐。例如,如果
long
具有4字节对齐方式,则
sizeof
应用于包含
long
struct
,并且
char
为8。建议我改为使用无符号int作为我的内部项[]类型,它将保存容器存储的值的地址。您是否建议不要使用void*?@doubleshot:不,不能在
无符号int
中存储指针值。在64位Windows或Linux上,一个地址是64位,但
unsigned int
只有32位,因此它完全不是初学者
void*
unsigned char*
都可以合理地用于存储任何对象的地址。