May 17, 2016
I'm weak enough with C pointers, but when I see char** my brain freezes up like a deer caught in headlights. Can anyone translate the below C call into D?



ALURE_API const ALCchar** ALURE_APIENTRY alureGetDeviceNames(ALCboolean all,ALCsizei *count)

// my poor attempt to Deify it

int count;
const char[][] allDevice = alureGetDeviceNames(true, &count);

// and the inevitable error

alure_stuff.d(190): Error: cannot implicitly convert expression ((*alureGetDeviceNames)(cast(byte)1, & count)) of type char** to const(char[][])



Thanks. (And I have been staring at docs for hours)
May 17, 2016
On 05/17/2016 09:37 PM, WhatMeWorry wrote:
> I'm weak enough with C pointers, but when I see char** my brain freezes
> up like a deer caught in headlights. Can anyone translate the below C
> call into D?

First things first: char** is a perfectly fine D type, of course. But you probably know that.

> ALURE_API const ALCchar** ALURE_APIENTRY alureGetDeviceNames(ALCboolean
> all,ALCsizei *count)
>
> // my poor attempt to Deify it
>
> int count;
> const char[][] allDevice = alureGetDeviceNames(true, &count);

char[][] is quite different from char**. While you can make a char[] from a char* by slicing the pointer, you can't make a char[][] from a char** in the same way, because the element type changes.

You need to make the char* -> char[] conversions individually and fill a new array with them:

----
import std.stdio: writeln;
import std.string: fromStringz;

void main()
{
    /* Step 1: Get the char** and the count. */
    int count;
    char** pp = alureGetDeviceNames(&count);

    /* Step 2: char** + count -> char*[] */
    char*[] pa = pp[0 .. count];

    /* Step 3: Iterate over the char*[] and convert the elements
    to char[]. Fill a newly allocated char[][] with them. */
    char[][] aa = new char[][](count);
    foreach (i, p; pa)
    {
        char[] a = fromStringz(p); /* char* -> char[] */
        aa[i] = a;
    }

    /* print to verify */
    writeln(aa); /* ["foo", "bar", "baz"] */
}

char** alureGetDeviceNames(int* count)
{
    /* just some test data */
    *count = 3;
    return ["foo\0".dup.ptr, "bar\0".dup.ptr, "baz\0".dup.ptr].ptr;
}
----

Note that this allocates a new array. Depending on the exact scenario, it may be worthwhile to stop at the char*[] stage instead, and work with null terminated strings.