Providing char** in Kotlin

Kotlin/Native allows to compile to a native application and use system libraries. Sometimes, this can be a little confusing at first, for example with pointers of pointers ...

Long Introduction

I stumbled over this type a short while ago: char**. At the time of writing this article, I'm creating a Koltin/Native application. The application calls the posix method execvp, which can be used to execute prorgams and has char** as second parameter. But what is a char**? Well, C doesn't have strings. Strings are represented as character arrays, which can be declared like this char myString[5];, which defnies a character array (string) of size 5. As function parameters (and sometimes also in other places), strings are declared like this char *myString, which means the pointer, a.k.a. the address, of a character array. It is also possible to declare and instantiate a string in C with char *myString = "hello world";. Here myString is also a character array.

Now, what is this: char *x[4];? This is an array of size 4 that contains pointers to character arrays. So it can be used in the following way:

char s1[] = "well";
char s2[] = "this";
char s3[] = "is";
char s4[] = "fun";
char *x[4]; x[0] = s1; x[1] = s2; x[2] = s3; x[3] = s4;

This code will create four character arrays (s1 to s4) and put their addresses into the array x. In other words, it's an array of strings. It is also something that can be put into a function that requires something of type char **, because this means "pointer to pointers of characters" which translates to "array of addresses of character arrays".

What does char** translate to in Kotlin? In Kotlin the corresponding type (at least for execvp) is:

CValuesRef<CPointerVar<ByteVar>>

Instead of char there is ByteVar. That's ok, because characters can be represented as numbers. CPointerVar is a pointer for a specific type (here ByteVar), so there's the character arrays. CValuesRef is a pointer for C values. In this case the C values are pointers of the form CPointerVar.

The actual problem

I hadn't worked with pointers of pointers in Kotlin before (the above type in particular), so the question that took me a while to answer was: How can a CValuesRef of CPointerVar of ByteVar be created?

To start from the back: a ByteArray can be created from a Kotlin String by calling the String function encodeToByteArray(). To get the pointer to the byte array, it needs to be pinned, for instance with calling pin() on it, which creates a Pinned<ByteArray>. The pinned array has a funtion addressOf(Int) that can be called with the parameter 0 to get the arrays start address. This can be done with multiple strings, so multiple byte array pointers are available. The final step is to get a pointer of an array of those pointers. This can be achieved by putting the array pointers into a list using listOf and calling the Kotlin/Native utility function toCValues() on that list.

For better understanding, here is how the whole process looks in code. This is the Kotlin translation of the previous example:

// encode and pin
val s1 = "well".encodeToByteArray().pin()
val s2 = "this".encodeToByteArray().pin()
val s3 = "is".encodeToByteArray().pin()
val s4 = "fun".encodeToByteArray().pin()
val x = listOf(s1, s2, s3, s4) .map {it.addressOf(0)} // get the pointers .toCValues() // tranform to C type array
// and unpin :-) s1.unpin() s2.unpin() s3.unpin() s4.unpin()

This code can be optimized, but I chose this way in order to go along with the above text.

The part that took me the most time was to find toCValues(). So, to summarize this article I can give this hint: When developing with Kotlin/Native it might be advisable to take a look into Types.kt and Utils.kt. They have a lot of useful content.