Thread overview
Converting a string[] to char**
May 09, 2017
David Zhang
May 09, 2017
rikki cattermole
May 09, 2017
ag0aep6g
May 09, 2017
Mike Parker
May 09, 2017
David Zhang
May 09, 2017
Stanislav Blinov
May 09, 2017
David Zhang
May 09, 2017
Hi,

I'm playing around with Vulkan, and part of its initialization code calls for an array of strings as char**. I've tried casting directly (cast(char**)) and breaking it down into an array of char*s (char*[]) before getting the pointer to its first element (&a[0]). It provides the correct type, but Vulkan rejects it. Is there a standard way of doing this?

I'm trying to set the ppEnabledExtensionNames member of VkInstanceCreateInfo.

Regards,
    David
May 09, 2017
On 09/05/2017 5:22 AM, David Zhang wrote:
> Hi,
>
> I'm playing around with Vulkan, and part of its initialization code
> calls for an array of strings as char**. I've tried casting directly
> (cast(char**)) and breaking it down into an array of char*s (char*[])
> before getting the pointer to its first element (&a[0]). It provides the
> correct type, but Vulkan rejects it. Is there a standard way of doing this?
>
> I'm trying to set the ppEnabledExtensionNames member of
> VkInstanceCreateInfo.
>
> Regards,
>     David

From docs:

"ppEnabledLayerNames is a pointer to an array of enabledLayerCount null-terminated UTF-8 strings containing the names of layers to enable for the created instance. See the Layers section for further details."

Note each string is null terminated.
You also have to set enabledLayerCount to the length of the string array.

There is toStringz in std.string that'll help here for null terminating.

If you're already doing all this, no idea then.
May 09, 2017
On 05/09/2017 06:22 AM, David Zhang wrote:
> I'm playing around with Vulkan, and part of its initialization code
> calls for an array of strings as char**. I've tried casting directly
> (cast(char**)) and breaking it down into an array of char*s (char*[])
> before getting the pointer to its first element (&a[0]). It provides the
> correct type, but Vulkan rejects it. Is there a standard way of doing this?
>
> I'm trying to set the ppEnabledExtensionNames member of
> VkInstanceCreateInfo.

`string[]` isn't compatible with what's expected from the `char**`. The function expects to get a bunch of `char*`s, tightly packed. A `string[]` isn't that. A single `string` is a pointer-and-length pair. So a `string[]` has pointers and lengths alternating in memory.

Casting from `string[]` to `char*[]` means reinterpreting string lengths as pointers. That's not what you want. When dereferencing those fake pointers, you'll get garbage values or crash the program.

You have to create a new array of pointers. As rikki cattermole has pointed out, you also have to null-terminate the individual strings, and pass the amount of pointers in a separate parameter.

----
import std.algorithm.iteration: map;
import std.array: array;
import std.conv: to;
import std.string: toStringz;

string[] strs = ["foo", "bar", "baz"];

/* convert string[] to char*[]: */
immutable(char)*[] chptrs = strs.map!toStringz.array;

immutable(char)** ppEnabledLayerNames = chptrs.ptr;
uint enabledLayerCount = chptrs.length.to!uint;
----
May 09, 2017
On Tuesday, 9 May 2017 at 05:38:24 UTC, ag0aep6g wrote:

> You have to create a new array of pointers. As rikki cattermole has pointed out, you also have to null-terminate the individual strings, and pass the amount of pointers in a separate parameter.
>
> ----
> import std.algorithm.iteration: map;
> import std.array: array;
> import std.conv: to;
> import std.string: toStringz;
>
> string[] strs = ["foo", "bar", "baz"];
>
> /* convert string[] to char*[]: */
> immutable(char)*[] chptrs = strs.map!toStringz.array;
>
> immutable(char)** ppEnabledLayerNames = chptrs.ptr;
> uint enabledLayerCount = chptrs.length.to!uint;
> ----

Although, if it's known that the array was populated with literals, toStringz isn't needed. String literals are automatically nul terminated.
May 09, 2017
On Tuesday, 9 May 2017 at 05:52:28 UTC, Mike Parker wrote:
> On Tuesday, 9 May 2017 at 05:38:24 UTC, ag0aep6g wrote:
>
>> You have to create a new array of pointers. As rikki cattermole has pointed out, you also have to null-terminate the individual strings, and pass the amount of pointers in a separate parameter.
>>
>> ----
>> import std.algorithm.iteration: map;
>> import std.array: array;
>> import std.conv: to;
>> import std.string: toStringz;
>>
>> string[] strs = ["foo", "bar", "baz"];
>>
>> /* convert string[] to char*[]: */
>> immutable(char)*[] chptrs = strs.map!toStringz.array;
>>
>> immutable(char)** ppEnabledLayerNames = chptrs.ptr;
>> uint enabledLayerCount = chptrs.length.to!uint;
>> ----
>
> Although, if it's known that the array was populated with literals, toStringz isn't needed. String literals are automatically nul terminated.

Thanks for all your answers.

The strings are all predefined statically for the moment, with a '\0' character at the end.

I take from this that there's no way to avoid allocating then? I had hoped... :(

If indeed there is no way to avoid allocation, do the allocations have to remain 'alive' for the duration of the instance? Or can I deallocate immediately afterwards? I can't seem to find it in the Vulkan spec.

May 09, 2017
On Tuesday, 9 May 2017 at 07:50:33 UTC, David  Zhang wrote:

> If indeed there is no way to avoid allocation, do the allocations have to remain 'alive' for the duration of the instance? Or can I deallocate immediately afterwards? I can't seem to find it in the Vulkan spec.

2.3.1. Object Lifetime:

> Application-owned memory is immediately consumed by any Vulkan command it is passed into. The application can alter or free this memory as soon as the commands that consume it have returned.
May 09, 2017
On Tuesday, 9 May 2017 at 07:59:19 UTC, Stanislav Blinov wrote:
> On Tuesday, 9 May 2017 at 07:50:33 UTC, David  Zhang wrote:
>
>> If indeed there is no way to avoid allocation, do the allocations have to remain 'alive' for the duration of the instance? Or can I deallocate immediately afterwards? I can't seem to find it in the Vulkan spec.
>
> 2.3.1. Object Lifetime:
>
>> Application-owned memory is immediately consumed by any Vulkan command it is passed into. The application can alter or free this memory as soon as the commands that consume it have returned.

I see, thanks.