Jump to page: 1 2
Thread overview
core.stdc.stdlib._compare_fp_t and qsort
Mar 11, 2018
Joe
Mar 11, 2018
Stefan Koch
Mar 12, 2018
Joe
Mar 12, 2018
Adam D. Ruppe
Mar 12, 2018
Joe
Mar 12, 2018
Adam D. Ruppe
Mar 12, 2018
H. S. Teoh
Mar 12, 2018
Seb
Mar 12, 2018
Joe
Mar 18, 2018
Joe
Mar 18, 2018
Dmitry Olshansky
Mar 18, 2018
Joe
Mar 18, 2018
Dmitry Olshansky
Mar 18, 2018
Dmitry Olshansky
Mar 18, 2018
Joe
Mar 18, 2018
Joe
March 11, 2018
I'm getting a compiler error in a qsort() call as follows:

    qsort(recs, num_recs, (Record *).sizeof, compar);

Record is a struct, recs is a fixed array of pointers to Record's and num_recs is a size_t that holds the number of valid records.

compar is this:

int compar(const void *p1, const void *p2)
{
    import core.stdc.string : strcmp;
    const Record **rp1 = cast(Record **)p1;
    const Record **rp2 = cast(Record **)p2;

    return strcmp((*rp1).name.ptr, (*rp2).name.ptr);
}

The error is: Error: function testd.compar (const(void*) p1, const(void*) p2) is not callable using argument types ()

I don't quite understand what those parentheses mean: is it implying "no arguments" and if so, where would one provide arguments?

Joe
March 11, 2018
On Sunday, 11 March 2018 at 23:12:30 UTC, Joe wrote:
> I'm getting a compiler error in a qsort() call as follows:
>
>     qsort(recs, num_recs, (Record *).sizeof, compar);
>
> Record is a struct, recs is a fixed array of pointers to Record's and num_recs is a size_t that holds the number of valid records.
>
> compar is this:
>
> int compar(const void *p1, const void *p2)
> {
>     import core.stdc.string : strcmp;
>     const Record **rp1 = cast(Record **)p1;
>     const Record **rp2 = cast(Record **)p2;
>
>     return strcmp((*rp1).name.ptr, (*rp2).name.ptr);
> }
>
> The error is: Error: function testd.compar (const(void*) p1, const(void*) p2) is not callable using argument types ()
>
> I don't quite understand what those parentheses mean: is it implying "no arguments" and if so, where would one provide arguments?
>
> Joe

You have to pass a pointer to the function.
Otherwise it'll be a parenthsis-less call.
use :  qsort(recs, num_recs, (Record *).sizeof, &compar);
March 12, 2018
On Sunday, 11 March 2018 at 23:26:04 UTC, Stefan Koch wrote:
> You have to pass a pointer to the function.
> Otherwise it'll be a parenthsis-less call.
> use :  qsort(recs, num_recs, (Record *).sizeof, &compar);

After passing a pointer, getting some other error messages, I changed the call to

    qsort(cast(void *)recs, num_recs, cast(size_t)(Record *).sizeof, &compar);

and the latest error is:

Error: function core.stdc.stdlib.qsort (scope void* base, ulong nmemb, ulong size, extern (C) int function(scope const(void*), scope const(void*)) @system compar) is not callable using argument types (void*, ulong, ulong, int function(const(void*) p1, const(void*) p2))

I fail to see which argument is causing the problem now.

Joe
March 12, 2018
On Monday, 12 March 2018 at 01:04:06 UTC, Joe wrote:
> and the latest error is:

D's error messages are so bad and shouldn't be hard to fix. It kills me that basic every-day functionality like this isn't a priority to the core devs. I even wrote a patch myself that would call this out but it didn't fit the code style so rejected. Ugh. But behold:

(scope void* base,
ulong nmemb,
ulong size,
extern (C) int function(scope const(void*), scope const(void*)) @system compar)

(void*,
ulong,
ulong,
int function(const(void*) p1, const(void*) p2))



I just reformatted it but now the difference should be visible: `extern(C)` is missing on your callback.

The scope things might make a difference too, but I know for sure extern(C) is necessary on your callback function.
March 11, 2018
On Mon, Mar 12, 2018 at 01:04:06AM +0000, Joe via Digitalmars-d-learn wrote:
> On Sunday, 11 March 2018 at 23:26:04 UTC, Stefan Koch wrote:
> > You have to pass a pointer to the function.
> > Otherwise it'll be a parenthsis-less call.
> > use :  qsort(recs, num_recs, (Record *).sizeof, &compar);
> 
> After passing a pointer, getting some other error messages, I changed the call to
> 
>     qsort(cast(void *)recs, num_recs, cast(size_t)(Record *).sizeof,
> &compar);
> 
> and the latest error is:
> 
> Error: function core.stdc.stdlib.qsort (scope void* base, ulong nmemb, ulong
> size, extern (C) int function(scope const(void*), scope const(void*))
> @system compar) is not callable using argument types (void*, ulong, ulong,
> int function(const(void*) p1, const(void*) p2))
> 
> I fail to see which argument is causing the problem now.
[...]

I wonder if the problem is because qsort expects a C linkage function (`extern (C) int function(...)`), but you're passing a D linkage (i.e., native) function to it.  You can't do that, because the order of arguments in a D linkage function may differ from a C linkage function, and could potentially cause a subtle bug if you're not expecting the arguments in a different order. (I actually ran into this myself, in a different context where there was no type enforcement like there is here, and it took me a long time to track down the problem.)

If indeed this is the problem, try adding `extern (C)` to your D function to make it compatible with C linkage, and that should do the trick.  I think.


T

-- 
If you look at a thing nine hundred and ninety-nine times, you are perfectly safe; if you look at it the thousandth time, you are in frightful danger of seeing it for the first time. -- G. K. Chesterton
March 12, 2018
On Monday, 12 March 2018 at 01:45:54 UTC, Adam D. Ruppe wrote:
> I just reformatted it but now the difference should be visible: `extern(C)` is missing on your callback.
>
> The scope things might make a difference too, but I know for sure extern(C) is necessary on your callback function.

I saw the extern(C) and I believe I tried it before my previous post, but dismissed it because I saw no difference in compiler behavior.  In any case declaring

extern (C) int compar(const (void *) p1, const (void *) p2) {
   ... // as before
}

still gives the error:

function core.stdc.stdlib.qsort (scope void* base, ulong nmemb, ulong size, extern (C) int function(scope const(void*), scope const(void*)) @system compar) is not callable using argument types (void*, ulong, ulong, extern (C) int function(const(void*) p1, const(void*) p2))

It only went away with

extern (C) int compar(scope const (void *) p1, scope const (void *) p2)

Could you explain or direct me to something that elucidates why the "scope" qualifiers are needed?  And is there something else that is necessary inside compar() or are the "scope"s just for decorative purposes?

Joe
March 12, 2018
On Sunday, 11 March 2018 at 23:12:30 UTC, Joe wrote:
> I'm getting a compiler error in a qsort() call as follows:
>
>     qsort(recs, num_recs, (Record *).sizeof, compar);
>
> Record is a struct, recs is a fixed array of pointers to Record's and num_recs is a size_t that holds the number of valid records.
>
> compar is this:
>
> int compar(const void *p1, const void *p2)
> {
>     import core.stdc.string : strcmp;
>     const Record **rp1 = cast(Record **)p1;
>     const Record **rp2 = cast(Record **)p2;
>
>     return strcmp((*rp1).name.ptr, (*rp2).name.ptr);
> }
>
> The error is: Error: function testd.compar (const(void*) p1, const(void*) p2) is not callable using argument types ()
>
> I don't quite understand what those parentheses mean: is it implying "no arguments" and if so, where would one provide arguments?
>
> Joe

Out of interest: I wonder what's your usecase for using qsort. Or in other words: why you can't use the high-level std.algorithm.sorting.sort?
March 12, 2018
On Monday, 12 March 2018 at 02:44:17 UTC, Joe wrote:
> I saw the extern(C) and I believe I tried it before my previous post, but dismissed it because I saw no difference in compiler behavior.

Yeah, the compiler should just tell you what specifically it is complaining about instead of making you hunt. These "no function match" errors are actually my #1 pain point as a daily D user... and as a regular D tech support rep, I see there are very frequent problems for everyone else too.

> Could you explain or direct me to something that elucidates why the "scope" qualifiers are needed?  And is there something else that is necessary inside compar() or are the "scope"s just for decorative purposes?

So `scope` means you promise not to escape the reference outside your scope; that you won't store the pointers somewhere else for future use.

It is defined here: https://dlang.org/spec/function.html#parameters tho that's pretty light.

The compiler only checks it if you throw some random -dipsomething switch. The idea is something similar to Rust's borrow checker. It aims to make it a compile error to sneak out pointers to temporaries through our callback. You wouldn't do that anyway with a compare function, but now it is an error to try ( if the strict enforcement thing is thrown. and i don't remember the name, they are all random dip numbers on the switches)

I'm actually mildly against adding these directly to C functions, but this attribute spam is being added to all the druntime definitions. It requires stuff like nothrow and nogc on a bunch of handlers too, ugh, but the idea behind it is to make sure you don't break the C function's documented rules, but here checked by the D compiler without needing any runtime wrappers/checks.



But until recently it wasn't checked at all which is why I wasn't sure if that was causing your error. I guess it is required to match the function call even if the strict enforcement isn't thrown now.
March 12, 2018
On Monday, 12 March 2018 at 03:13:08 UTC, Seb wrote:
> Out of interest: I wonder what's your usecase for using qsort. Or in other words: why you can't use the high-level std.algorithm.sorting.sort?

This is only temporary. I will be using std.algorithm.sorting.sort. I was converting a C program and it annoyed me that I couldn't get the qsort invocation past the D compiler.
March 18, 2018
On Monday, 12 March 2018 at 03:50:42 UTC, Joe wrote:
> On Monday, 12 March 2018 at 03:13:08 UTC, Seb wrote:
>> Out of interest: I wonder what's your usecase for using qsort. Or in other words: why you can't use the high-level std.algorithm.sorting.sort?
>
> This is only temporary. I will be using std.algorithm.sorting.sort. I was converting a C program and it annoyed me that I couldn't get the qsort invocation past the D compiler.

Now that I'm trying to use std.algorithm.sorting, I'm again puzzled by what I need to use for the "less" predicate. My first try was:

   sort!((a, b) => to!string((*a).name) < to!string((*b).name))(recs);

This results in the error:

Error: template std.algorithm.sorting.sort cannot deduce function from argument types !((a, b) => to!string((*a).name) < to!string((*b).name))(Record*[10]), candidates are:
/usr/lib/ldc/x86_64-linux-gnu/include/d/std/algorithm/sorting.d(1851):        std.algorithm.sorting.sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) if ((ss == SwapStrategy.unstable && (hasSwappableElements!Range || hasAssignableElements!Range) || ss != SwapStrategy.unstable && hasAssignableElements!Range) && isRandomAccessRange!Range && hasSlicing!Range && hasLength!Range)

which is not very helpful. It's a bit different from the "no function match" that Adam complains about, but I presume it's because now we're dealing with templates, and although the compiler finds a single candidate, it's not satisfactory but it can't tell the user anything further.

I've tried using fromStringz((*x).name.ptr) instead of to!string (I'm still unclear to what extent can templates be used within templates).  I also tried using an explicit cast(Record *)x because I'm also unsure that type information is passed down.  Neither change helped.
« First   ‹ Prev
1 2