我需要实现一个可以使用任何类型的简单动态数组。
现在,我的void**
实现比直接使用int*
慢50%:
#define N 1000000000
// Takes ~6 seconds
void** a = malloc(sizeof(void*) * N);
for (int i =0; i < N; i++) {
*(int*)(&a[i]) = i;
}
printf("%d\n", *(int*)&a[N-1]);
// Takes ~3 seconds
int* b = malloc(sizeof(int) * N) ;
for (int i =0; i < N; i++) {
b[i] = i;
}
printf("%d\n", b[N-1]);
我不是C专家。有更好的方法吗?
谢谢
修改
看起来像使用void**
是一个坏主意。有没有一种方法可以通过void*
来实现?
这是在Go中实现的方式:
type slice struct {
array unsafe.Pointer
len int
cap int
}
我想做类似的事情。
edit2
我设法用void*
来实现。
解决方案非常简单:
void* a = malloc(sizeof(int) * N);
for (int i = 0; i < N; i++) {
((int*)a)[i] = i;
}
printf("%d\n", ((int*)a)[N-1]);
现在的性能是一样的。
答案 0 :(得分:3)
您的两个替代程序并不相似。在第二个有效的空间中,您分配足以容纳N
整数的空间,然后将值分配给该空间的int
大小的成员。但是,在第一个中,您要分配足够大的空间以容纳N
个指向void的指针,然后在不初始化这些指针的情况下,尝试为它们所指向的对象分配值。即使这些指针已初始化为指向int
对象,也存在额外的间接访问级别。
从某种意义上说,您的第一个代码可以更正:
void** a = malloc(sizeof(void*) * N);
for (int i =0; i < N; i++) {
a[i] = (void *) i;
}
printf("%d\n", (int) a[N-1]);
这依赖于这样的事实,即C允许在指针和整数类型之间进行转换(尽管不一定会造成数据丢失),并且请注意,只有一个间接级别(数组索引),而不是两个。
由于您未定义第一个替代方案的实施行为,因此我们只能推测其运行速度较慢的原因。但是,如果我们假设实现简单明了,那么可能会由于所有数组写入的缓存局部性差而导致性能下降。
答案 1 :(得分:0)
请注意,sizeof(void *)
是64位处理器(8字节地址与4字节有符号整数)上sizeof(int)
的两倍。如果是这种情况,我敢打赌,区别仅在于页面缓存丢失。您的存储单元需要多加载两倍的页面,这很慢(link for more information here)。
还请注意,C ++向量不是“可以与任何类型一起使用的动态数组”。它们绑定到一个类型,例如:std::vector<int>
是一个动态数组,但是您只能在其中存储int
。
解决您的问题的方法是在C中实现某种std::vector<void *>
。但这效率不高:
答案 2 :(得分:0)
我设法用void*
来实现。
解决方案非常简单:
void* a = malloc(sizeof(int) * N);
for (int i =0;i<N;i++) {
((int*)a)[i] = i;
}
printf("%d\n", ((int*)a)[N-1]);
现在的性能是一样的。
我也碰到了这篇很棒的文章,解释了如何在C中实现通用数据结构: