Spec-Zone.ru › Kotlin 1.7

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

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

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

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

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

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

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

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

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

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

  • указатели

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

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

  • тип boolean (из 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++ на Stackoverflow содержатся более подробные сведения об этом.

Для каждого набора .h файлов вы будете использовать инструмент cinterop из Kotlin/Native для генерации Kotlin/Native библиотеки или .klib. Сгенерированная библиотека будет мостить вызовы из Kotlin/Native в C. Она включает соответствующие Kotlin объявления для определений из файлов .h. Достаточно иметь файл .h для запуска инструмента cinterop. И вам не нужно создавать файл 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 и плагина multiplatform для взаимодействия с C.

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

Используйте следующий build.gradle(.kts) файл Gradle:

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

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 = "6.7.1"
  distributionType = Wrapper.DistributionType.BIN
}
plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '1.7.20'
}

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 = '6.7.1'
  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

Исправьте код

Вы увидели все определения, и пришло время исправить код. Запустите задачу runDebugExecutableNative Gradle в 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 Сопоставление структур и объединений типов из C – учебник

© 2010–2022 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