[英]Void pointer arithmetic and dereference
我正在研究一个用于通用目的的快速排序实现,快速排序 function 的参数之一是一个void
指针,我看到了 void 指针上的 ff 算术,所以我想知道它实际上是做什么的,如果它甚至可能吗?
void _qsort(void *v, int size, int left, int right, int (*comp)(void *, void *));
void swap(void *v1, void *v2, int size) {
char buffer[size];
memcpy(buffer, v1, size);
memcpy(v1, v2, size);
memcpy(v2, buffer, size);
}
这部分出现在上面定义的快速排序的主体中:
void *vl = (char *)(v + (left * size));
void *vr = (char *)(v + (mid * size));
swap(vl, vr, size);
所以从上面的代码,
void
指针v
进行算术运算,例如v + (left * size)
?void *vl = (char *)(v + (left * size));
是什么意思? 部分是什么意思? 尚未转换为char
指针,如果是,我们为什么要将它分配给void
指针?swap
部分,到底发生了什么,比如vl
和vr
是否改变了它们的 memory 位置、值或其他什么?您假设正确:C 标准不允许对void
指针进行算术运算。
您正在查看的程序使用gcc 、 clang 、 tcc和许多其他程序支持的通用编译器扩展,它在void
指针上实现算术,就好像它们是字节指针一样。 有了这个扩展, v + (left * size)
表现为
(void *)((char *)v + (left * size))
所以声明void *vl = (char *)(v + (left * size));
相当于:
void *vl = (char *)((void *)((char *)v + (left * size)));
请注意,整个表达式在 C 中被隐式转换为(void *)
。
这个声明可以简化为:
void *vl = (char *)v + left * size;
这可能是程序员想要写的,他们的错误没有被报告,因为编译器允许void *
算术具有完全相同的效果。
关于您的第三个问题, swap
function 使用size
字节的局部可变长度数组buffer
交换v1
和v2
指向的 memory 块的内容。 qsort
通常以相当小的元素大小调用,因此这种方法是可以的,但是允许使用非常长的元素(超过几兆字节)的数组调用qsort
,这可能会导致堆栈溢出。
这是一个更安全的实现:
void swap(void *v1, void *v2, size_t size) {
unsigned char *p1 = v1;
unsigned char *p2 = v2;
while (size >= 8) {
char buffer[8];
memcpy(buffer, p1, sizeof buffer);
memcpy(p1, p2, sizeof buffer);
memcpy(p2, buffer, sizeof buffer);
p1 += sizeof buffer;
p2 += sizeof buffer;
size -= sizeof buffer;
}
if (size > 0) {
if (size >= 4) {
char buffer[4];
memcpy(buffer, p1, sizeof buffer);
memcpy(p1, p2, sizeof buffer);
memcpy(p2, buffer, sizeof buffer);
p1 += sizeof buffer;
p2 += sizeof buffer;
size -= sizeof buffer;
}
while (size > 0) {
unsigned char temp = *p1;
*p1 = *p2;
*p2 = temp;
p1++;
p2++;
size--;
}
}
}
另请注意以下备注:
标准库 function qsort
有一个不同的原型:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
不建议将int
用于大小和索引值,并且对于 64 位系统上的大型数组, left * size
可能会溢出。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.