gpt4 book ai didi

c - 在Mac和Linux上qsort_r的不同声明

转载 作者:IT王子 更新时间:2023-10-29 00:17:15 26 4
gpt4 key购买 nike

让我们看一下Linux中的qsort_r函数(/usr/include/stdlib.h):

typedef int (*__compar_d_fn_t)(const void *, const void *, void *);

extern void qsort_r (void *__base, size_t __nmemb, size_t __size,
__compar_d_fn_t __compar, void *__arg)
__nonnull ((1, 4));

让我们看看Mac中的 qsort_r函数( /usr/include/stdlib.h):
void qsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *));

如您所见,这些声明彼此不同(参数顺序)。这真是令人惊讶!在某个地方提示解决这个问题是否有效?

最佳答案

Will it be effective to complain somewhere to solve this problem?



las,不。这种方式已经存在了很长时间,并且有太多的代码依赖于此。

我认为根本的问题是“为什么会发生这些不兼容”?我会回答。它似乎可以归结为BSD首先实现它,但界面较差。 ISO和更高版本的GNU修复了该接口(interface),并认为兼容性破坏是值得的。微软会尽其所能。

正如@Downvoter(大名)所指出的那样, qsort_r是非标准函数。如果它是标准的,那就太好了,但是您不能依靠它。 qsort_s是C11附件K中的一种标准,但是没有人真正实现C11,更不用说其附件和 whether Annex K is a good idea is in question了。

像许多C和Unix问题一样,这归结为BSD,GNU和Microsoft以及它们无法协调C扩展。 Linux是GNU。 OS X杂乱无章,但对于C而言,它遵循BSD。

FreeBSD在2002年9月添加了 qsort_r。Visual Studio 2005具有稍微不同的 qsort_s。 ISO在2007年再次将形式化为 qsort_s。终于,几年后,GNU终于在2008年出现在glibc 2.8中,显然是在遵循ISO。 Here's an old thread spanning 2004 to 2008 requesting qsort_r be implemented in glibc具有一些基本原理。

为了提醒大家,这是C99中定义的 qsort
void qsort(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *)
);

FreeBSD是2002年9月的第一个。他们决定 qsort_r应该打破 qsort接口(interface),并将“thunk”自变量放在比较函数之前。
void qsort_r(
void *base, size_t nmemb, size_t size,
void *thunk,
int (*compar)(void *, const void *, const void *)
);

为什么?您将不得不询问 Garrett Wollman是谁编写了补丁。查看 the patch,从他对 CMP的更改中可以看出,认为先“thunk”是个好模式。也许他们认为“比较功能要走到最后”是人们会记住的。不幸的是,这意味着 qsortqsort_r的比较函数的参数相反。很困惑。

同时,曾经是创新者的微软拥有 qsort_s in Visual Studio 2005
void qsort_s(
void *base, size_t num, size_t width,
int (__cdecl *compare )(void *, const void *, const void *),
void * context
);

“s”代表“安全”,而不是“r”代表“可重入”,其他人可能都遵循ISO约定(请参阅下文),反之亦然。他们将“thunk”放在 qsort_s的末尾,使参数与 qsort相同,但是为了最大程度地避免混淆,“thunk”放在比较函数(如BSD)的开头。他们选择了最糟糕的选择。

更糟糕的是,ISO在2007年发布了 TR 24731-1,将边界检查添加到C标准库中(感谢@JonathanLeffler指出了这一点)。是的,他们有自己的 qsort_r,但是它叫做 qsort_s!是的,它不同于其他所有人!
errno_t qsort_s(
void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context
);

他们明智地决定将 qsort_s及其比较函数的参数保留为 qsort的超集,可能是认为这样会使人们更容易记住。他们增加了一个返回值,可能是一个好主意。更令人困惑的是,当时这是“技术报告”,不是C标准的一部分。现在是C11标准的“附件K”,仍然是可选的,但重量更大。

GNU做出了相同的决定,可能遵循ISO的 qsort_s
void qsort_r(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg
);

查看 the glibc patch adding qsort_r 可能也更容易实现。要确定要知道,您必须询问Ulrich Drepper。

多年来,BSD决定用 qsort交换参数及其比较功能的决定可能引起了很多困惑和错误。 ISO/GNU决定使它们保持相同的决定可以说是更好的选择。 ISO决定给它起一个不同的名字。 GNU决定破坏与BSD功能的兼容性。微软决定做任何事情。现在,我们陷入了四个不兼容的实现中。由于比较函数具有不同的签名,因此兼容性宏是不平凡的。

(这都是对代码的重新构造。对于它们的实际原理,您必须深入研究邮件列表文件。)

我不能真正责怪GNU或BSD或ISO或Microsoft ...好的,我可以责怪Microsoft故意杀死C。Point是标准化C,扩展该标准并让编译器遵循该标准的过程。缓慢而痛苦的是,编译器编写者有时不得不做些权宜之计。

关于c - 在Mac和Linux上qsort_r的不同声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39560773/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com