macOS和Linux下qsort()结果存在无法解释的差异
我最近有个学生在他们的比较仪里写道:macOS和Linux下qsort()结果存在无法解释的差异,c,linux,macos,gcc,clang,C,Linux,Macos,Gcc,Clang,我最近有个学生在他们的比较仪里写道: int comparator (const void *p, const void *q) { const data_t *indexp = *(data_t **)p; const data_t *indexq = *(data_t **)q; return indexp->index > indexq->index; } 这在Ubuntu16.04LTS下运行没有问题,但在macOS下运行时无法正确排序。只需将
int comparator (const void *p, const void *q) {
const data_t *indexp = *(data_t **)p;
const data_t *indexq = *(data_t **)q;
return indexp->index > indexq->index;
}
这在Ubuntu16.04LTS下运行没有问题,但在macOS下运行时无法正确排序。只需将
更改为-
,就足以让它在两种平台上运行
那么,这里发生了什么?我能想到的唯一一件事是,这个不等式意味着-1
值的丢失,但是qsort()
的Linux(或GCC)实现显然没有受到影响
这怎么可能
编辑:
我想检查这是否是特定于编译器的,所以我在Ubuntu 16.04下使用了clang进行编译,没有任何更改,它在那里工作得很好。因此,我认为libc与macOS(BSD-libc?)中实际的
qsort()
实现是导致这种情况发生的原因。我真的很想知道那是什么 使用>
确实是一个bug。此操作将只产生0或1的结果。使用-
是正确的方法
它对其中一个有效而对另一个无效的原因很可能是因为要排序的列表最初是如何排序的。如果有疑问,请在Linux上运行代码。不必指出OP中的比较器函数不正确,使用它是未定义的行为。尽管如此,问它是如何工作的还是很有趣的
虽然
qsort
的接口需要一个返回整数的比较器函数,提供三个可能的返回值,但是qsort
实现没有义务使用所有这些信息。它可能总是执行相同的简单双向分支。这类似于,如果第一个参数严格小于第二个参数,则其比较器返回布尔值true
当然,您的学生的comparator函数永远不会表明第一个参数严格小于第二个参数,这将为测试类似于以下内容的实现带来问题:
if (*cmp(p, q) < 0) ...
(或者,相当于,
我应该在Valgrind下寻找什么?该学生有一些无关的“未初始化值”问题,我已经解决了,但这个问题仍然存在。列表中的数据是完全随机的,尽管奇怪的是(在macOS下),一些较大的值被正确地放置在数组的末尾(比如1000),但越接近数组的开头,较小的值就会被混淆。@chrissphinx查找内存边界之外的任何读/写实例。这指向未定义的行为。可能更好return(indexp->index>indexq->index)-(indexp->indexindex)
(避免溢出的可能性,并处理,
)@chrissphinx用于检查您的qsort使用有一个自动工具,似乎有点工作。对于足够小的整数值,例如在减去值时没有溢出,则减法是可以的。当值足够大时,减法不再安全,因为溢出。重要的是,如果比较器(v1,v2)
返回一个正值,比较器(v2,v1)
必须返回一个负值(反之亦然),如果一个比较结果返回0,那么另一个也必须返回0。通常,在qsort
调用中,您将执行const data*indexp=p;
并调用qsort
如:data\t p,q;…;qsort(&p,&q,n,comparator)
。您如何调用qsort
?qsort需要一个。C++20实际上得到了一个三向比较运算符,这样您就可以用该语言执行return indexp->index indexq->index;
。不确定C2x是否也在使用它
if (*cmp(p, q) > 0) ...
while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
left_ptr += size;
while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
right_ptr -= size;
if ((*cmp) (b1, b2, arg) <= 0)
/* If the memory requirements are too high don't allocate memory. */
if (size / pagesize > (size_t) phys_pages)
{
_quicksort (b, n, s, cmp, arg);
return;
}
while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
if (cmp_result == 0) {
swap_cnt = 1;
swap(pa, pb);
pa += es;
}
pb += es;
}
while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
if (cmp_result == 0) {
swap_cnt = 1;
swap(pc, pd);
pd -= es;
}
pc -= es;
}