Взаимодействие с Си

В Ü имеется ограниченная возможность взаимодействовать с кодом на Си. Можно вызывать функции, написанные на Си из Ü. Также можно вызывать функции, написанные на Ü из Си.

Для взаимодействия с Си в Ü есть ряд механизмов.

Функции без кодирования имён

В отличие от Си, в Ü имена обычных функции специальным образом кодируются, чтобы итоговые полные имена перегруженных функций или функций в различных пространствах имён различались. Чтобы отменить такое кодирование, надо пометить функцию модификатором nomangle, указанным после fn и опционального модификатора constexpr. Имя функции, помещенное таким образом, будет тем же, каким бы оно было в Си. Соответственно, такую функцию можно будет вызвать из Си. Также можно будет пометить таким образом прототип функции, реализованной на Си, для возможности вызова её из Ü.

fn nomangle SDL_Quit() : void;

fn MyQuit()
{
    SDL_Quit(); // Вызываем внешнюю функцию
}

// Функция, доступная в Си коде
fn nomangle SomeFoo() : i32
{
    return 0;
}

nomangle функции имеют ряд ограничений:

  • Операторы не могут быть nomangle
  • Функции-члены структур или классов не могут быть nomangle
  • nomangle функции могут быть расположены только в глобальном пространстве имён
  • Нельзя перегружать nomangle функции

Cоглашения о вызове

Функции и указатели на функию могут иметь указание соглашения о вызове. Оно указывается после перечисления списка параметров функции и после unsafe (если таковой есть).

fn Foo() call_conv("C");
fn Bar(i32 x) unsafe call_conv("fast") {}
fn nomangle Baz(f32 x, f32 y) call_conv("system"){}

var (fn() call_conv("C")) ptr = Foo;

Существуют следующие имена соглашений о вызовах: C, default, Ü, fast, cold, system.

C - стандартное соглашение о вызове, использующееся в языках Си и C++. default и Ü это псевдонимы для C. Также, если не указано соглашение о вызове, оно будет равно C. Для взаимодействия с Си и C++ кодом следует использовать именно это соглашение о вызове.

fast и cold - соглашения для соответственно быстрого или компактного вызова. Они не совместимы со схожими соглашениями в других языках, так что использовать их можно только в Ü коде, и то, если это даёт ощутимый эффект.

system - это платформозависимый псевдоним для системных функций. На большинстве платформ это псевдоним для соглашения C. На 32-битной Windows это псевдоним для stdcall соглашения, которое используется в WinAPI.

Структуры с упорядоченными полями

Обычные структуры и классы в Ü имеют неопределённый порядок полей. Компилятор имеет право упорядочить их, как ему удобно. В Си же поведение иное - поля структур там упорядочены в порядке объявления. Для того, чтобы получить порядок полей структур, как в Си, существует специальный модификатор - ordered. Данный модификатор указывается при объявлении структуры или класса, после опциональных вида класса, родительских классов, модификатора non_sync. Структура объявленная с таким модификатором будет иметь тот же порядок полей, что аналогичная структура в Си.

В примере ниже две данные структуры будут аналогичны.

Ü код
 struct A ordered
 {
     bool x;
     i32 y;
     bool z;
 }
C++ код
 struct A
 {
     bool x;
     int32_t y;
     bool z;
 };

Ограничения и предостережения взаимодействия с Си

Не каждую функцию на Ü можно вызвать из Си и наоборот. Существует ряд ограничений, накладываемых на вызов. Компилятор Ü не знает, что какая-та функция реализована на Си, и поэтому не может проверить правильность вызова. Поэтому соблюдение правил возложено на программиста.

Аргументы-значения и возвращаемые значения функций должны быть фундаментального типа, типа перечисления, типа указателя на функцию или сырого указателя. Составные типы (структуры/классы, массивы, кортежи) для значений не поддерживаются. При этом можно передавать в функцию и возвращать из функции ссылки, они аналогичны указателям в Си.

Структуры, передаваемые в Си код, или получаемые из него, должны иметь одинаковый состав и порядок полей в Ü и в Си. Исключения составляют структуры, к полям которых нету обращений из Ü и которые передаются в Си по одиночке (не массивом). Такие структуры могут не иметь аналогичного состава полей, главное, чтобы их размер и выравнивание были не меньше, чем в Си.

Кортежи в Ü по размещению в памяти аналогичны структурам в Си, с тем же набором и порядком типов элементов, что в кортеже. Поэтому в Си коде следует использовать структуры-аналоги для кортежей Ü.

В Си коде не действует контроль ссылок. Поэтому надо быть особо внимательным при взаимодействии с Си кодом.

Для большей безопасности рекомендуется помечать как unsafe функции, реализованные на Си. Это заставит пользователя таких функций оборачивать вызов этих функций в unsafe блок и придаст больше внимательности.