解释 qsort 中的 C 代码行

Posted

技术标签:

【中文标题】解释 qsort 中的 C 代码行【英文标题】:Explain line of C code in qsort 【发布时间】:2018-05-16 03:11:29 【问题描述】:

我一直在研究 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);

...代码继续

【问题讨论】:

您的链接中的代码没有这样的行。它只是说PUSH (NULL, NULL);。你是从哪里得到这个版本的,你为什么还要以这种形式查看它? 以上代码为后期预处理 【参考方案1】:

不,它不是函数指针声明。这只是一种令人费解的说法

top->lo = 0;
top->hi = 0;
++top;

您可以使用, 运算符将以上内容重写为单个表达式语句

top->lo = 0, top->hi = 0, ++top;

然后添加不必要的演员表

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

还有一堆多余的()s

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

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

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

现在您有了原始版本。

我不清楚为什么有人决定将这种奇怪的语法与 , 运算符和大量冗余 () 一起使用。看起来像一个宏扩展。也许它是一段已经预处理的代码? ((void *) 0) 部分可能很容易成为标准 NULL 宏的预处理器替代品。

【讨论】:

这很有帮助。谢谢。这是后期宏扩展。【参考方案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 中。使用额外的()s 是为了确保++top--top 以正确的顺序发生inline

当我们看到 qsort.c 顶部的 Copyright (C) 1991 - 2017 消息时,它以这种方式实现的原因就更清楚了... 1991 年的编译器可能在内联方面真的很糟糕功能。

【讨论】:

以上是关于解释 qsort 中的 C 代码行的主要内容,如果未能解决你的问题,请参考以下文章

如何解释 C 预处理器输出中的 # 前缀行?

C库qsort()的简单模拟实现

qsort库函数排序

解释 1 行 C 代码并将其翻译成 Python [重复]

为啥 stdlib 中的 qsort 不适用于双精度值? [C]

C ++中的构造函数初始化[重复]