解释qsort中的一行C代码

4
我一直在查看不同的qsort实现,并且在这里找到了源代码(https://code.woboq.org/userspace/glibc/stdlib/qsort.c.html)中有一行我不明白的内容。它看起来像是一个函数指针声明。希望得到任何帮助。为了回答这个问题,我已经包含了尽可能多的代码(并标注了该行),如果还有需要,请告诉我,谢谢。
typedef struct
{
    char *lo;
    char *hi;

} stack_node;


void _quicksort (void *const pbase, size_t total_elems, size_t size, cmp_t cmp, void *arg)
{

    char *base_ptr = (char *) pbase;

    const size_t max_thresh = 4 * size;

    if (total_elems == 0)

        return;

    if (total_elems > 4)
    {
        char *lo = base_ptr;
        char *hi = &lo[size * (total_elems - 1)];
        stack_node stack[(8 * sizeof(size_t))];
        stack_node *top = stack;

        /* Line below is a function pointer declaration?  Initializes struct? */

        ((void) ((top->lo = (((void*)0))), (top->hi = (((void*)0))), ++top));

        while ((stack < top))
        {
            char *left_ptr;
            char *right_ptr;

            char *mid = lo + size * ((hi - lo) / size >> 1);

... code goes on


你链接中的代码没有这样的行。它只是说 PUSH (NULL, NULL);。你从哪里获取了这个版本,为什么要以这种形式查看它? - AnT stands with Russia
以上代码是后处理。 - Corry Chapman
2个回答

7
不,这不是函数指针声明。它只是一种复杂的方式来表达
top->lo = 0;
top->hi = 0;
++top;

您可以使用逗号运算符将上述内容重写为单个表达式语句。
top->lo = 0, top->hi = 0, ++top;

然后添加不必要的强制转换。
top->lo = (void *) 0, top->hi = (void *) 0, ++top;

以及许多冗余的()标记

(top->lo = (((void *) 0))), (top->hi = (((void *) 0))), ++top;

然后将整个内容转换为(void)(比如,为了抑制任何潜在的编译器警告,表达式结果被“未使用”)。

((void) ((top->lo = (((void *) 0))), (top->hi = (((void *) 0))), ++top));

现在您已经有了原始版本。

为什么有人决定使用那种奇怪的语法,包括大量的冗余括号和逗号运算符,我无法理解。看起来像是宏展开。也许这是已经预处理过的代码片段?((void *) 0) 的部分很容易被预处理器替换为标准的 NULL 宏。


这非常有帮助。谢谢。这是宏展开后的结果。 - Corry Chapman

2

查看URL,我们发现这一行实际上是一个宏定义,特别是

/* The next 4 #defines implement a very fast in-line stack abstraction. */
/* The stack needs log (total_elements) entries (we could even subtract
   log(MAX_THRESH)).  Since total_elements has type size_t, we get as
   upper bound for log (total_elements):
   bits per byte (CHAR_BIT) * sizeof(size_t).  */

#define STACK_SIZE        (CHAR_BIT * sizeof(size_t))
#define PUSH(low, high)   ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
#define POP(low, high)    ((void) (--top, (low = top->lo), (high = top->hi)))
#define STACK_NOT_EMPTY   (stack < top)

实际上,代码出现在PUSH的定义中,其补充出现在POP中。使用额外的()是为了确保++top--top发生inline并按正确顺序进行。

这种实现方式的原因在于我们看到qsort.c顶部的版权信息版权所有(C)1991-2017时更加清晰... 1991年的编译器可能非常糟糕,无法内联函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接