Spec-Zone.ru › Kotlin 2

Отображение указателей на функции из C — руководство

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

Для некоторых API нативных платформенных библиотек, поставляемых вместе с Kotlin/Native (например, Foundation, UIKit и POSIX), требуется opt-in.

Давайте рассмотрим, какие указатели на функции C доступны из Kotlin, а также изучим расширенные сценарии взаимодействия Kotlin/Native с C и сборки Gradle для мультиплатформенных проектов.

В этом руководстве вы:

  • Узнаете, как передать функцию Kotlin в качестве указателя на функцию C

  • Используете указатели на функции C из Kotlin

Отображение типов указателей на функции из C

Чтобы понять, как типы Kotlin сопоставляются с типами C, объявим две функции: одну, принимающую указатель на функцию в качестве параметра, и другую, возвращающую указатель на функцию.

В первой части серии вы уже создали библиотеку C с необходимыми файлами. Для этого шага обновите объявления в файле interop.def после разделителя ---:


---

int myFun(int i) {
  return i+1;
}

typedef int  (*MyFun)(int);

void accept_fun(MyFun f) {
  f(42);
}

MyFun supply_fun() {
  return myFun;
}

Файл 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!")
    
        accept_fun(/* fix me*/)
        val useMe = supply_fun()
    }
    
  2. Используйте команду IntelliJ IDEA Перейти к объявлению (Cmd + B/Ctrl + B), чтобы перейти к следующему сгенерированному API для функций C:

    fun myFun(i: kotlin.Int): kotlin.Int
    fun accept_fun(f: kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlin.Int) -> kotlin.Int>>? /* from: interop.MyFun? */)
    fun supply_fun(): kotlinx.cinterop.CPointer<kotlinx.cinterop.CFunction<(kotlin.Int) -> kotlin.Int>>? /* from: interop.MyFun? */
    

Как видите, указатели на функции C представлены в Kotlin с помощью CPointer<CFunction<...>>. Функция accept_fun() принимает указатель на функцию в качестве необязательного параметра, а supply_fun() возвращает указатель на функцию.

CFunction<(Int) -> Int> представляет сигнатуру функции, а CPointer<CFunction<...>>? — nullable-указатель на функцию. Для всех типов CPointer<CFunction<...>> доступна функция-расширение оператора .invoke(), позволяющая вызывать указатели на функции как обычные функции Kotlin.

Передача функции Kotlin в качестве указателя на функцию C

Пора попробовать использовать функции C из кода Kotlin. Вызовите функцию accept_fun() и передайте указатель на функцию C в лямбда-функцию Kotlin:

import interop.*
import kotlinx.cinterop.staticCFunction
import kotlinx.cinterop.ExperimentalForeignApi

@OptIn(ExperimentalForeignApi::class)
fun myFun() {
    accept_fun(staticCFunction<Int, Int> { it + 1 })
}

В этом вызове используется вспомогательная функция staticCFunction {} из Kotlin/Native, чтобы преобразовать лямбда-функцию Kotlin в указатель на функцию C. Она поддерживает только несвязанные лямбда-функции, не захватывающие переменные. Например, такая функция не может захватывать локальную переменную из функции, а только глобально видимые объявления.

Убедитесь, что функция не выбрасывает исключения. Выбрасывание исключений из staticCFunction {} приводит к недетерминированным побочным эффектам.

Использование указателя на функцию C из Kotlin

Следующий шаг — вызвать указатель на функцию C, возвращённый вызовом supply_fun():

import interop.*
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.invoke

@OptIn(ExperimentalForeignApi::class)
fun myFun2() {
    val functionFromC = supply_fun() ?: error("No function is returned")

    functionFromC(42)
}

Kotlin преобразует возвращаемый тип указателя на функцию в nullable-объект CPointer<CFunction<>. Сначала нужно явно проверить его на null, поэтому в приведённом выше коде используется оператор Elvis. Инструмент cinterop позволяет вызывать указатель на функцию C как обычную функцию Kotlin: functionFromC(42).

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

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

import interop.*
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.invoke
import kotlinx.cinterop.staticCFunction

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

    val cFunctionPointer = staticCFunction<Int, Int> { it + 1 }
    accept_fun(cFunctionPointer)

    val funFromC = supply_fun() ?: error("No function is returned")
    funFromC(42)
}

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

./gradlew runDebugExecutableMacosArm64

Следующий шаг

В следующей части серии вы узнаете, как строки сопоставляются между Kotlin и C:

  • Предыдущий шаг

  • Следующий шаг

См. также

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

1 сентября 2026 г.
Отображение типов структур и объединений из C — руководствоОтображение строк из C — руководство

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

Spec-Zone.ru

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