qsort() 和铸造操作
qsort() and casting operation
考虑一个指向结构的指针数组。以下代码取自您可能会找到的示例 here。我想对这两排演员表进行解释。我不熟悉这个 "double casting".
int myptrstructcmp(const void *p1, const void *p2)
{
struct mystruct *sp1 = *(struct mystruct * const *)p1;
struct mystruct *sp2 = *(struct mystruct * const *)p2;
我认为应该是:
int myptrstructcmp(const void *p1, const void *p2)
{
struct mystruct *sp1 = (struct mystruct *)p1;
struct mystruct *sp2 = (struct mystruct *)p2;
假设您要对 int
的数组进行排序。您的比较器将传递一对伪装成 void *
的 int *
;添加了一层间接。
如果您正在对 struct mystruct *
的数组进行排序,您的比较器将被 struct mystruct **
伪装成 void *
;添加了一层间接。
What is the meaning of struct mystruct * const *
? Without the const*
it fails to cast correctly. Why?
'without the const *
it fails to cast correctly' 是什么意思?没有 const
,它工作正常。如果没有第二个 *
,它就无法工作,因为函数被传递了一个 struct mystruct **
(给予或接受一些常量),如果你省略了第二个星号,你就是在滥用类型系统。
考虑:
struct mystruct
{
int i;
};
int myptrstructcmp(const void *p1, const void *p2);
int myptrstructcmp(const void *p1, const void *p2)
{
struct mystruct *sp1 = *(struct mystruct **)p1;
struct mystruct *sp2 = *(struct mystruct **)p2;
if (sp1->i < sp2->i)
return -1;
else if (sp1->i > sp2->i)
return +1;
else
return 0;
}
这编译得很好。当您在 **
之间添加 const
时,它也可以正常编译。就个人而言,我不会在转换中包含 const
。我要做的是对 sp1
和 sp2
指针进行常量限定:
struct mystruct const *sp1 = *(struct mystruct **)p1;
struct mystruct const *sp2 = *(struct mystruct **)p2;
或:
const struct mystruct *sp1 = *(struct mystruct **)p1;
const struct mystruct *sp2 = *(struct mystruct **)p2;
这承诺不会修改它们在函数中指向的对象,这实际上对 qsort()
的正确性能至关重要。
这是您的线索 — 在您参考的 C FAQ 中:
If, on the other hand, you're sorting pointers to structures, you'll need indirection,
您正在对指向结构的指针列表进行排序。必须按排序在列表中处理指针,这意味着您通过引用(通过指向指针的指针)传递列表中的指针以进行比较。
来自man qsort
:
[...] comparison function [..] which is called with two arguments that point to the objects being compared.
"被比较的对象" 是传递给 qsort()
的数组的元素,因为这个要排序的数组包含 指针 比较函数接收指向指针的指针作为参数。
要从传递给比较函数的参数中获取数组的元素,这些参数需要取消引用。
比较函数接收指向数组元素的指针。如果您的数组包含某种类型 T
的元素,那么您的比较函数将接收 const void *
指针,这些指针应被解释为 const T *
指针。
在你的例子中 T
等于 struct mystruct *
(因为你的数组包含指针)。在那种情况下 const T *
等同于 struct mystruct * const*
,这正是您在代码中看到的。
为了让您的代码更容易理解,您实际上可以在函数中引入一个 typedef 名称 T
并将您的 conversions/dereferences 拆分为单独的步骤
int myptrstructcmp(const void *p1, const void *p2)
{
typedef mystruct *T; // array elements are pointers
const T *pel1 = p1, *pel2 = p2; // pointers to array elements
T sp1 = *pe1, sp2 = *pe2; // values of array elemnts
这等同于您在原始代码中的内容;
考虑一个指向结构的指针数组。以下代码取自您可能会找到的示例 here。我想对这两排演员表进行解释。我不熟悉这个 "double casting".
int myptrstructcmp(const void *p1, const void *p2)
{
struct mystruct *sp1 = *(struct mystruct * const *)p1;
struct mystruct *sp2 = *(struct mystruct * const *)p2;
我认为应该是:
int myptrstructcmp(const void *p1, const void *p2)
{
struct mystruct *sp1 = (struct mystruct *)p1;
struct mystruct *sp2 = (struct mystruct *)p2;
假设您要对 int
的数组进行排序。您的比较器将传递一对伪装成 void *
的 int *
;添加了一层间接。
如果您正在对 struct mystruct *
的数组进行排序,您的比较器将被 struct mystruct **
伪装成 void *
;添加了一层间接。
What is the meaning of
struct mystruct * const *
? Without theconst*
it fails to cast correctly. Why?
'without the const *
it fails to cast correctly' 是什么意思?没有 const
,它工作正常。如果没有第二个 *
,它就无法工作,因为函数被传递了一个 struct mystruct **
(给予或接受一些常量),如果你省略了第二个星号,你就是在滥用类型系统。
考虑:
struct mystruct
{
int i;
};
int myptrstructcmp(const void *p1, const void *p2);
int myptrstructcmp(const void *p1, const void *p2)
{
struct mystruct *sp1 = *(struct mystruct **)p1;
struct mystruct *sp2 = *(struct mystruct **)p2;
if (sp1->i < sp2->i)
return -1;
else if (sp1->i > sp2->i)
return +1;
else
return 0;
}
这编译得很好。当您在 **
之间添加 const
时,它也可以正常编译。就个人而言,我不会在转换中包含 const
。我要做的是对 sp1
和 sp2
指针进行常量限定:
struct mystruct const *sp1 = *(struct mystruct **)p1;
struct mystruct const *sp2 = *(struct mystruct **)p2;
或:
const struct mystruct *sp1 = *(struct mystruct **)p1;
const struct mystruct *sp2 = *(struct mystruct **)p2;
这承诺不会修改它们在函数中指向的对象,这实际上对 qsort()
的正确性能至关重要。
这是您的线索 — 在您参考的 C FAQ 中:
If, on the other hand, you're sorting pointers to structures, you'll need indirection,
您正在对指向结构的指针列表进行排序。必须按排序在列表中处理指针,这意味着您通过引用(通过指向指针的指针)传递列表中的指针以进行比较。
来自man qsort
:
[...] comparison function [..] which is called with two arguments that point to the objects being compared.
"被比较的对象" 是传递给 qsort()
的数组的元素,因为这个要排序的数组包含 指针 比较函数接收指向指针的指针作为参数。
要从传递给比较函数的参数中获取数组的元素,这些参数需要取消引用。
比较函数接收指向数组元素的指针。如果您的数组包含某种类型 T
的元素,那么您的比较函数将接收 const void *
指针,这些指针应被解释为 const T *
指针。
在你的例子中 T
等于 struct mystruct *
(因为你的数组包含指针)。在那种情况下 const T *
等同于 struct mystruct * const*
,这正是您在代码中看到的。
为了让您的代码更容易理解,您实际上可以在函数中引入一个 typedef 名称 T
并将您的 conversions/dereferences 拆分为单独的步骤
int myptrstructcmp(const void *p1, const void *p2)
{
typedef mystruct *T; // array elements are pointers
const T *pel1 = p1, *pel2 = p2; // pointers to array elements
T sp1 = *pe1, sp2 = *pe2; // values of array elemnts
这等同于您在原始代码中的内容;