Spec-Zone.ru › Kotlin 1.9

Картирование примитивных типов данных из C – учебник

В этом учебнике вы узнаете, какие типы данных C видны в Kotlin/Native и наоборот. Вы будете:

  • Увидеть, какие типы данных используются в языке C.

  • Создать небольшую библиотеку на C, которая использует эти типы в экспорте.

  • Просмотреть сгенерированные Kotlin API из библиотеки на C.

  • Узнать, как примитивные типы в Kotlin сопоставляются с C.

Типы данных языка C

Какие типы данных существуют в языке C? Давайте возьмем статью типов данных C из Википедии в качестве основы. В языке программирования C есть следующие типы:

  • базовые типы char, int, float, double с модификаторами signed, unsigned, short, long

  • структуры, объединения, массивы

  • указатели

  • указатели на функции

Также существуют более специфичные типы:

  • логический тип (из C99)

  • size_t и ptrdiff_t (также ssize_t)

  • целые типы с фиксированной шириной, такие как int32_t или uint64_t (из C99)

Также в языке C есть следующие квалификаторы типов: const, volatile, restruct, atomic.

Лучший способ увидеть, какие типы данных C видны в Kotlin, — это попробовать.

Пример библиотеки на C

Создайте файл lib.h, чтобы увидеть, как функции C отображаются в Kotlin:

#ifndef LIB2_H_INCLUDED
#define LIB2_H_INCLUDED

void ints(char c, short d, int e, long f);
void uints(unsigned char c, unsigned short d, unsigned int e, unsigned long f);
void doubles(float a, double b);

#endif

В файле отсутствует блок extern "C", который не нужен для этого примера, но может потребоваться, если вы используете C++ и перегруженные функции. В разделе совместимости с C++ на Stack Overflow содержится более подробная информация об этом.

Для каждой группы файлов .h вы будете использовать инструмент cinterop из Kotlin/Native для генерации библиотеки Kotlin/Native или .klib. Сгенерированная библиотека будет обеспечивать вызовы из Kotlin/Native в C. Она включает соответствующие Kotlin-объявления для определений из файлов .h. Для запуска инструмента cinterop достаточно иметь файл .h. И вам не нужно создавать файл lib.c, если вы не хотите скомпилировать и запустить пример. Более подробная информация об этом содержится на странице взаимодействия с C. Для учебника достаточно создать файл lib.def со следующим содержимым:

headers = lib.h

Вы можете включить все объявления непосредственно в файл .def после разделителя ---. Это может быть полезно для включения макросов или других определений C в код, генерируемый инструментом cinterop. Тела методов также компилируются и полностью включаются в двоичный файл. Используйте эту функцию, чтобы иметь работающий пример без необходимости в компиляторе C. Для этого нужно добавить реализации функций C из файла lib.h и поместить эти функции в файл .def. У вас будет следующий результат interop.def:

---

void ints(char c, short d, int e, long f) { }
void uints(unsigned char c, unsigned short d, unsigned int e, unsigned long f) { }
void doubles(float a, double b) { }

Файла interop.def достаточно для компиляции и запуска приложения или открытия его в IDE. Теперь пришло время создать файлы проекта, открыть проект в IntelliJ IDEA и запустить его.

Просмотр сгенерированных Kotlin API для библиотеки на C

Хотя можно использовать командную строку, как напрямую, так и в сочетании с файлом сценария (таким как файл .sh или .bat), этот подход не масштабируется для больших проектов с сотнями файлов и библиотек. В таком случае лучше использовать компилятор Kotlin/Native с системой сборки, поскольку она помогает загружать и кешировать двоичные файлы и библиотеки компилятора Kotlin/Native с транзитными зависимостями и запускать компилятор и тесты. Kotlin/Native может использовать систему сборки Gradle через плагин kotlin-multiplatform.

Основы создания проекта, совместимого с IDE, с помощью Gradle, мы рассмотрели в учебнике «Базовое приложение Kotlin/Native». Пожалуйста, ознакомьтесь с ним, если вы ищете подробные начальные шаги и инструкции по началу работы с новым проектом Kotlin/Native и его открытию в IntelliJ IDEA. В этом учебнике мы рассмотрим расширенные примеры использования Kotlin/Native и многоплатформенных сборок с Gradle для взаимодействия с C.

Сначала создайте папку проекта. Все пути в этом учебнике будут относительными к этой папке. Иногда необходимо создать отсутствующие директории перед добавлением новых файлов.

Используйте следующий файл сборки Gradle:

plugins {
    kotlin("multiplatform") version "1.9.0"
}

repositories {
    mavenCentral()
}

kotlin {
  linuxX64("native") { // on Linux
  // macosX64("native") { // on x86_64 macOS
  // macosArm64("native") { // on Apple Silicon macOS
  // mingwX64("native") { // on Windows
    val main by compilations.getting
    val interop by main.cinterops.creating
    
    binaries {
      executable()
    }
  }
}

tasks.wrapper {
  gradleVersion = "7.6"
  distributionType = Wrapper.DistributionType.BIN
}
plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '1.9.0'
}

repositories {
    mavenCentral()
}

kotlin {
  linuxX64('native') { // on Linux
  // macosX64("native") { // on x86_64 macOS
  // macosArm64("native") { // on Apple Silicon macOS
  // mingwX64('native') { // on Windows
    compilations.main.cinterops {
      interop 
    }
    
    binaries {
      executable()
    }
  }
}

wrapper {
  gradleVersion = '7.6'
  distributionType = 'BIN'
}

В файле проекта настраивается взаимодействие с C как дополнительный шаг сборки. Переместим файл interop.def в каталог src/nativeInterop/cinterop. Gradle рекомендует использовать соглашения вместо конфигураций, например, файлы исходных кодов должны находиться в папке src/nativeMain/kotlin. По умолчанию все символы из C импортируются в пакет interop, и вы можете захотеть импортировать весь пакет в файлы .kt. Ознакомьтесь с документацией плагина kotlin-multiplatform, чтобы узнать обо всех возможных способах его настройки.

Создайте файл-заглушку src/nativeMain/kotlin/hello.kt со следующим содержимым, чтобы увидеть, как объявления примитивных типов данных C видны из Kotlin:

import interop.*

fun main() {
  println("Hello Kotlin/Native!")
  
  ints(/* fix me*/)
  uints(/* fix me*/)
  doubles(/* fix me*/)
}

Теперь вы готовы открыть проект в IntelliJ IDEA и посмотреть, как исправить пример проекта. При этом посмотрите, как примитивные типы данных C отображаются в Kotlin/Native.

Примитивные типы в Kotlin

С помощью IntelliJ IDEA (Перейти | Объявление) или ошибок компилятора вы увидите сгенерированный API для функций C:

fun ints(c: Byte, d: Short, e: Int, f: Long)
fun uints(c: UByte, d: UShort, e: UInt, f: ULong)
fun doubles(a: Float, b: Double)

Типы C сопоставлены ожидаемым образом, обратите внимание, что тип char отображается как kotlin.Byte, так как обычно это знаковое 8-битное значение.

C

Kotlin

char

kotlin.Byte

unsigned char

kotlin.UByte

short

kotlin.Short

unsigned short

kotlin.UShort

int

kotlin.Int

unsigned int

kotlin.UInt

long long

kotlin.Long

unsigned long long

kotlin.ULong

float

kotlin.Float

double

kotlin.Double

Исправление кода

Вы увидели все определения, и пришло время исправить код. Запустите задачу Gradle runDebugExecutableNative в IDE или используйте следующую команду для запуска кода:

./gradlew runDebugExecutableNative

Конечный код в файле hello.kt может выглядеть так:

import interop.*

fun main() {
  println("Hello Kotlin/Native!")
  
  ints(1, 2, 3, 4)
  uints(5, 6, 7, 8)
  doubles(9.0f, 10.0)
}

Дальнейшие шаги

Продолжайте изучать более сложные типы языка C и их представление в Kotlin/Native в следующих учебниках:

  • Картирование структур и объединений из C

  • Картирование указателей на функции из C

  • Картирование строк из C

Документация по взаимодействию с C охватывает более сложные сценарии взаимодействия.

Последнее изменение: 16 февраля 2022
Взаимодействие с C Сопоставление типов struct и union из C – учебник

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

Spec-Zone.ru

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