www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Converting a string[] to char**

reply David Zhang <straivers98 gmail.com> writes:
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 08
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
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 08
prev sibling parent reply ag0aep6g <anonymous example.com> writes:
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 08
parent reply Mike Parker <aldacron gmail.com> writes:
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 08
parent reply David Zhang <straivers98 gmail.com> writes:
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
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
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
parent David Zhang <straivers98 gmail.com> writes:
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.
May 09