Mergesort that has `man 3 qsort` ANSI C prototype I have taken a look at these review questions: one, two, three and four and would still like to ask you to review my implementation of mergesort that follows the man 3 qsort prototype.

void *malloc_or_exit(size_t size) {
    void *tmp = malloc(size);

    if (tmp == NULL) {

        if (size == 0) {
            return tmp;
        }

        fprintf(
            stderr, "Failed to malloc %zu bytes: %s",
            size, strerror(errno)
        );

        exit(EXIT_FAILURE);
    }

    return tmp;
}

void mergesort0(
    void *xs, size_t n, size_t s,
    int (*cmp) (const void *, const void *)
) {
    if (n == 0 || n == 1) return;

    const size_t nlft = n / 2;
    const size_t nrgt = n - nlft;

    void *ys = (char *)xs + nlft * s;

    mergesort0(xs, nlft, s, cmp);
    mergesort0(ys, nrgt, s, cmp);

    void *const as = malloc_or_exit(n * s);
    void *const bs = (char *)as + nlft * s;
    void *const cs = (char *)as + n * s;

    memcpy(as, xs, n * s);

    void const *i = as;
    void const *j = bs;
    while (i != bs &amp;&amp; j != cs) {
        if (cmp(i, j) &lt;= 0) {
            memcpy(xs, i, s);
            i = (char *)i + s;
        } else {
            memcpy(xs, j, s);
            j = (char *)j + s;
        }

        xs = (char *)xs + s;
    }

    for (; i != bs; i = (char *)i + s, xs = (char *)xs + s) {
        memcpy(xs, i, s);
    }

    for (; j != cs; j = (char *)j + s, xs = (char *)xs + s) {
        memcpy(xs, j, s);
    }

    free(as);
}

#include &lt;stdio.h&gt;
int main() {
    int xs[] = {1, 2, 3, 4, 5};
    int ys[] = {5, 4, 3, 2, 1};
    int zs[] = {3, 1, 2, 4, 5};
    int as[] = {1, 1, 1};
    int bs[] = {3, 2, 2};

    int len = 5;

    qsort(zs, len, sizeof(int), compare_int);

    for (int i = 0; i &lt; len; ++i) {
        printf("%d ", *(zs + i));
    } printf("\n");
}
Better show your includes too, that makes evaluating your code easier and more meaningful.
Anyway, it's &lt;stdlib.h&gt;, &lt;stdio.h&gt; and &lt;string.h&gt;.
You know you can combine multiple conditions into a single expression with &amp;&amp;?
You can avoid all those casts if you use char* instead of void* internally.
Why don't you reuse a single allocation instead of doing n*log(n) ones, each local?
You know doing a single combined memcpy is far more efficient than multiple consecutive smaller ones?
If you only move the first nlft elements out of the way, you only need half the extra-space and save on copying.


Your test-program:


Your test-program doesn't seem to exercise your code...
You lost a newline at the end of your test-program.


Modified code:

#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

void* malloc_or_exit(size_t size) {
    void* result = malloc(size);

    if (!result &amp;&amp; size) {
        fprintf(
            stderr, "Failed to malloc %zu bytes: %s",
            size, strerror(errno)
        );
        exit(EXIT_FAILURE);
    }

    return result;
}

static void mergesort0_impl(
    char* as, char* xs, size_t n, size_t s,
    int (*cmp) (const void*, const void*)
) {
    if (n &lt; 2) return;

    const size_t nlft = n / 2;
    const size_t nrgt = n - nlft;

    char* ys = xs + nlft * s;

    mergesort0_impl(as, xs, nlft, s, cmp);
    mergesort0_impl(as, ys, nrgt, s, cmp);

    char* const bs = as + nlft * s;

    memcpy(as, xs, nlft * s);

    const char* i = as;
    const char* j = ys;
    for (; i != bs &amp;&amp; j != xs; xs += s) {
        if (cmp(i, j) &lt;= 0) {
            memcpy(xs, i, s);
            i += s;
        } else {
            memcpy(xs, j, s);
            j += s;
        }
    }
    if (i != bs)
        memcpy(xs, i, bs - i);
}

void mergesort0(
    void* xs, size_t n, size_t s,
    int (*cmp) (const void*, const void*)
) {
    if(n &lt; 2) return;
    void* as = malloc_or_exit(n / 2 * s);
    mergesort0_impl(as, xs, n, s, cmp);
    free(as);
}


#include &lt;stdio.h&gt;

void test(int nr, const int xs[], size_t n) {
    int* a = malloc_or_exit(2 * n * sizeof *xs);
    int* b = a + n;
    memcpy(a, xs, n * sizeof *xs);
    memcpy(b, xs, n * sizeof *xs);
    qsort(a, n, sizeof *a, compare_int);
    mergesort0(b, n, sizeof *b, compare_int);
    printf("Test %d %s: ", nr, !memcmp(a, b, n * sizeof *xs) ? "OK" : "FAILED");
    for (size_t i = 0; i &lt; n; ++i)
        printf("%d%c", xs[i], " \n"[i == n - 1]);
    free(a);
}

int main() {
    int xs[] = {1, 2, 3, 4, 5};
    int ys[] = {5, 4, 3, 2, 1};
    int zs[] = {3, 1, 2, 4, 5};
    int as[] = {1, 1, 1};
    int bs[] = {3, 2, 2};
    int nr = 0;
    #define TEST(a) test(nr++, a, sizeof a / sizeof *a)
    TEST(xs);
    TEST(ys);
    TEST(zs);
    TEST(as);
    TEST(bs);
    #undef TEST
}