Can anyone confirm if `char**` in C is represented...
# kotlin-native
b
Can anyone confirm if
char**
in C is represented as
CPointerVar<Char>
in kotlin?
v
On Linux I've seen it mapped mostly as
CPointerVar<ByteVar>
Assuming you are working on GTK, I've used the following for most of the
char**
-related conversions.
Copy code
/**
 * Convert a Kotlin [List<String>] into its native equivalent.
 */
public fun List<String>.toCStringList(scope: MemScope): CArrayPointer<CPointerVarOf<CPointer<ByteVar>>> = with(scope) {
    return allocArrayOf(this@toCStringList.map { it.cstr.getPointer(this) } + null)
}

/**
 * Convert a native char** into a Kotlin [List<String>].
 */
public fun CArrayPointer<CPointerVarOf<CPointer<ByteVar>>>.toKStringList(): List<String> = buildList {
    var i = 0
    while (this@toKStringList[i] != null) {
        add(this@toKStringList[i]!!.toKString())
        i++
    }
}
PoC code, this won't work for all methods. As sometimes the
char**
is null-terminated, and sometimes it has a fixed size
b
Thanks
Do type** in c always mean an array or are there other ways to represent an array in C?
v
not always an array, could also be a pointer to pointer
in the GTK case, you'll see
**
for GError out pointers, where you want to pass in a pointer to a
GError
pointer, so GTK can fill it with a pointer to the error when it encounters an error
b
Are you saying there is no standard way to declare an array in C, but rather just type** convention?
v
I'm not super fluent in C, so there might be other ways. In the case of string "arrays" here, the
char**
means a pointer to the first element in an array of
char*
and c strings, if I'm not mistaken, are also "arrays", and
char*
means a pointer to the first element in an array of
char
, And C-strings are an array of
char
terminated by
\0
b
Odd, why not null terminated?...
v
so for the
char**
case for GTK null-terminated string arrays, in memory it will look like
[ptr, ptr, ptr, null]
. where each
ptr
points to
[char, char, char, \0]
, something like that
b
Thanks, that's super clear now. I remember having to do some pointer voodoo like this back at the university and not liking it very much 😀
v
in the case of C strings, the
\0
is a null byte (because char is typically byte). In the case of
char**
since it's an array of pointers, the final element is a
null
pointer
b
Ah, makes sense now
v
also cinterop handles the C-strings for you mostly. and you can use
toKstring()
to convert it to a Kotlin String. and you can do
myKotlinString.cstr
to get a
char*
pointer to the c-String for your kotlin string
b
Yeah, I'm aware of those. Just trying to understand how it all ties together under the hood.
l
C does let you declare
char* strings[size];
, which is explicitly an array. I believe Kotlin will read this as a CArrayPointer turns out it’s CValuesRef. CArrayPointer comes from allocArray.
For a real world example, the FFmpeg sws_scale sees
*uint8_t* *const srcSlice[]
as
srcSlice: CValuesRef<CPointerVar<uint8_tVar>>
in Kotlin
e
C arrays decay to pointers across most boundaries
l
Also, small pedantic note on \0 vs null (NULL in C). Both are actually the same! ‘\0’ is just a nice way of saying 0, and so is NULL. C doesn’t really have a strong concept of runtime types, like Kotlin or Java. You could set
char c = (char) NULL
just as easily. In the same way,
char** words
is essentially equivalent to
char* words[]
. C also lets you do interesting things like
2[words] = "This works"
or
*(words + 3) = "This works too"
. C has been around for a long time, so there’s a lot of variations on almost anything. Some lists, like strings, use a null terminator, and others, like the srcSlice I mentioned earlier will require you to calculate the size (the calculation for srcSlice length is not fun) or know it.
e
in theory, standard C doesn't mandate that NULL is represented by 0, only that it is integer convertible to/from 0, but it does mandate that a byte with all bits set to 0 is interpreted as a null character
https://c-faq.com/null/machexamp.html has some specific examples of historical architectures where NULL was not physically zero
l
C is just one of those languages that gets more terrifying as you look further into it. No wonder one of my professors in college refused to acknowledge that anything past ANSI C exists...