A linear search implementation for any data type in C
I think you have chosen some of your types poorly. You write:

long long linear_search
    (
        const void *base, const void *x, const long long len, const int width,
        const int (*compare)(const void *, const void *)
    );


If you take a look at the definition of bsearch, you would do well to be inspired by that function. Obviously, someone thought about how it will work, and also there's the "principle of least surprise" to consider: why should two search functions have different argument types or return different results? Or even pass their arguments in different orders?

Let's change the parameter names, and compare:

long long linear_search(const void *ptr, const void *key, const long long count, const int size, const int (*comp)(const void*, const void*));
void*     bsearch      (const void *key, const void *ptr,       size_t    count,    size_t size,       int (*comp)(const void*, const void*));


Parameter Order

The search function puts the key first, then the details of the array to be searched. Why?

Because the key isn't related to anything else in the parameter list, and it's the "important" thing in the search expression:  Find me a needle! In this haystack, of such and such size. Use this comparator.

I'd suggest you reorder your parameters to conform with this. Not only is it a more sensible arrangement, it keeps your search function consistent with the "standard" search function. That means less to learn, and less chance for a silly bug.

Parameter Names

base, x, len, width, compare


versus

key, ptr, count, size, comp


I actually prefer base to ptr, but len and width aren't super clear. count and size are better in that regard.

Parameter Types

Your parameters are pointers, an array size, and a memory size. You got void * correct as the base type of the pointers (const because no changes). The array size and memory size should be size_t. 

The numeric parameters, and the compare-function return type, do not need to be declared const. Declaring them const is a promise not to change them - but they're function arguments (&amp; a return value)! Who cares if you change them, it's not like you're going to give them back! Get rid of those const declarations, since they provide no value to the caller.

Return Type

The bsearch function returns a pointer, rather than an index. Why?

Because it just found a pointer, and it's easier and faster to return the result that it has, instead of doing any math to maintain both a pointer and an index, or doing math to convert from pointer to index. 

Also, because the likely next operation for the user who calls a search function will be to use the result of the call, which will require computing a pointer.

If you choose not to use a pointer, you will need a signed integral type that is adequate to store any array index. That would be ptrdiff_t, since it is signed and can express any value of the form (&amp;a[i] - a). So long long should be replaced, either by void * or by ptrdiff_t.

Note that the return type of bsearch is declared as void * rather than const void *. Why? Because the data being searched is probably not constant, and that's the "most compatible" type - you can assign it to pretty much anything with less required casting than other options (char *, const void *, etc.).