Spec-Zone.ru › Kotlin 2

Сопоставление строк из C — руководство

Импорт библиотек C находится в статусе бета-версии. Все объявления Kotlin, сгенерированные инструментом cinterop из библиотек C, должны иметь аннотацию @ExperimentalForeignApi.

Для библиотек нативной платформы, поставляемых с Kotlin/Native (например, Foundation, UIKit и POSIX), согласие на использование требуется только для некоторых API.

В заключительной части серии рассмотрим, как работать со строками C в Kotlin/Native.

В этом руководстве вы узнаете, как:

  • Передать строку Kotlin в C

  • Прочитать строку C в Kotlin

  • Получить байты строки C в строку Kotlin

Работа со строками C

В C нет специального типа строк. Сигнатуры методов или документация помогут определить, представляет ли данный char * строку C в конкретном контексте.

Строки в языке C завершаются нулевым символом, поэтому в конец последовательности байтов добавляется завершающий ноль \0, обозначающий конец строки. Обычно используются строки в кодировке UTF-8. В кодировке UTF-8 используются символы переменной ширины, и она обратно совместима с ASCII. По умолчанию Kotlin/Native использует кодировку UTF-8.

Чтобы понять, как строки сопоставляются между Kotlin и C, сначала создайте заголовки библиотеки. В первой части серии вы уже создали библиотеку C с необходимыми файлами. Для этого шага:

  1. Обновите файл lib.h, добавив следующие объявления функций для работы со строками C:

    #ifndef LIB2_H_INCLUDED
    #define LIB2_H_INCLUDED
    
    void pass_string(char* str);
    char* return_string();
    int copy_string(char* str, int size);
    
    #endif
    

    В этом примере показаны распространённые способы передачи строки в языке C или её получения. Аккуратно обработайте возвращаемое значение функции return_string(). Используйте правильную функцию free() для освобождения возвращённого char*.

  2. Обновите объявления в файле interop.def после разделителя ---:

    ---
    
    void pass_string(char* str) {
    }
    
    char* return_string() {
      return "C string";
    }
    
    int copy_string(char* str, int size) {
        *str++ = 'C';
        *str++ = ' ';
        *str++ = 'K';
        *str++ = '/';
        *str++ = 'N';
        *str++ = 0;
        return 0;
    }
    

Файл interop.def содержит всё необходимое для компиляции и запуска приложения или его открытия в IDE.

Изучение сгенерированных API Kotlin для библиотеки C

Посмотрим, как объявления строк C сопоставляются с Kotlin/Native:

  1. В src/nativeMain/kotlin обновите файл hello.kt из предыдущего руководства, добавив следующее содержимое:

    import interop.*
    import kotlinx.cinterop.ExperimentalForeignApi
    
    @OptIn(ExperimentalForeignApi::class)
    fun main() {
        println("Hello Kotlin/Native!")
    
        pass_string(/*fix me*/)
        val useMe = return_string()
        val useMe2 = copy_string(/*fix me*/)
    }
    
  2. Используйте команду IntelliJ IDEA «Перейти к объявлению» (Cmd + B/Ctrl + B), чтобы перейти к следующему сгенерированному API для функций C:

    fun pass_string(str: kotlinx.cinterop.CValuesRef<kotlinx.cinterop.ByteVarOf<kotlin.Byte> /* from: kotlinx.cinterop.ByteVar */>?)
    fun return_string(): kotlinx.cinterop.CPointer<kotlinx.cinterop.ByteVarOf<kotlin.Byte> /* from: kotlinx.cinterop.ByteVar */>?
    fun copy_string(str: kotlinx.cinterop.CValuesRef<kotlinx.cinterop.ByteVarOf<kotlin.Byte> /* from: kotlinx.cinterop.ByteVar */>?, size: kotlin.Int): kotlin.Int
    

Эти объявления просты. В Kotlin указатели C char * сопоставляются с str: CValuesRef<ByteVarOf>? для параметров и с CPointer<ByteVarOf>? для типов возвращаемых значений. Тип char в Kotlin представлен как kotlin.Byte, поскольку обычно это 8-битовое значение со знаком.

В сгенерированных объявлениях Kotlin str определён как CValuesRef<ByteVarOf<Byte>>?. Поскольку этот тип допускает значение null, в качестве аргумента можно передать null.

Передача строк Kotlin в C

Попробуем использовать API из Kotlin. Сначала вызовите функцию pass_string():

import interop.*
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.cstr

@OptIn(ExperimentalForeignApi::class)
fun passStringToC() {
    val str = "This is a Kotlin string"
    pass_string(str.cstr)
}

Передать строку Kotlin в C просто благодаря String.cstr свойству-расширению. Для случаев с символами UTF-16 также есть свойство String.wcstr.

Чтение строк C в Kotlin

Теперь получите возвращаемое значение char * из функции return_string() и преобразуйте его в строку Kotlin:

import interop.*
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.toKString

@OptIn(ExperimentalForeignApi::class)
fun passStringToC() {
    val stringFromC = return_string()?.toKString()

    println("Returned from C: $stringFromC")
}

Здесь функция-расширение .toKString() преобразует строку C, возвращённую функцией return_string(), в строку Kotlin.

В Kotlin предусмотрено несколько функций-расширений для преобразования строк C char * в строки Kotlin — в зависимости от кодировки:

fun CPointer<ByteVarOf<Byte>>.toKString(): String // Standard function for UTF-8 strings
fun CPointer<ByteVarOf<Byte>>.toKStringFromUtf8(): String // Explicitly converts UTF-8 strings
fun CPointer<ShortVarOf<Short>>.toKStringFromUtf16(): String // Converts UTF-16 encoded strings
fun CPointer<IntVarOf<Int>>.toKStringFromUtf32(): String // Converts UTF-32 encoded strings

Получение байтов строки C из Kotlin

На этот раз используйте функцию C copy_string(), чтобы записать строку C в заданный буфер. Она принимает два аргумента: указатель на область памяти, куда следует записать строку, и допустимый размер буфера.

Функция также должна возвращать значение, указывающее, успешно ли она выполнилась. Предположим, что 0 означает успех и что переданный буфер достаточно велик:

import interop.*
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.usePinned

@OptIn(ExperimentalForeignApi::class)
fun sendString() {
    val buf = ByteArray(255)
    buf.usePinned { pinned ->
        if (copy_string(pinned.addressOf(0), buf.size - 1) != 0) {
            throw Error("Failed to read string from C")
        }
    }

    val copiedStringFromC = buf.decodeToString()
    println("Message from C: $copiedStringFromC")
}

Сначала в функцию C передаётся нативный указатель. Функция-расширение .usePinned() временно закрепляет нативный адрес в памяти байтового массива. Функция C заполняет байтовый массив данными. Другая функция-расширение, ByteArray.decodeToString(), преобразует байтовый массив в строку Kotlin, предполагая кодировку UTF-8.

Обновление кода Kotlin

Теперь, когда вы знаете, как использовать объявления C в коде Kotlin, попробуйте применить их в своём проекте. Код в итоговом файле hello.kt может выглядеть так:

import interop.*
import kotlinx.cinterop.*

@OptIn(ExperimentalForeignApi::class)
fun main() {
    println("Hello Kotlin/Native!")

    val str = "This is a Kotlin string"
    pass_string(str.cstr)

    val useMe = return_string()?.toKString() ?: error("null pointer returned")
    println(useMe)

    val copyFromC = ByteArray(255).usePinned { pinned ->
        val useMe2 = copy_string(pinned.addressOf(0), pinned.get().size - 1)
        if (useMe2 != 0) throw Error("Failed to read a string from C")
        pinned.get().decodeToString()
    }

    println(copyFromC)
}

Чтобы убедиться, что всё работает как ожидается, запустите задачу Gradle runDebugExecutable<YourTargetName> в IDE или выполните в терминале консольную команду, например:

./gradlew runDebugExecutableMacosArm64
  • Предыдущий шаг

Что дальше

Подробнее см. в документации «Взаимодействие с C», где рассматриваются более сложные сценарии.

1 сентября 2026 г.
Сопоставление указателей на функции из C — руководствоKotlin/Native в виде динамической библиотеки — руководство

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/mapping-strings-from-c.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API