0Pricing
Learn Rust Coding · Урок

Интерфейс внешних функций (FFI)

Научитесь вызывать библиотеки C из Rust и предоставлять функции Rust другим языкам с помощью FFI для обеспечения совместимости.

«Интерфейс внешних функций (FFI)» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 1 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 3 уроков всего.

Что такое FFI

FFI расшифровывается как интерфейс внешних функций. Это способ, позволяющий программам, написанным на одном языке программирования, вызывать функции или использовать структуры данных, определённые на другом языке.

В Rust FFI позволяет взаимодействовать с кодом, написанным на других языках, чаще всего на C. Это особенно полезно для интеграции с существующими библиотеками или системными интерфейсами программирования.

Зачем нужен FFI

FFI не является повседневным инструментом, но он незаменим, когда Вам требуется:

  • Использовать существующие библиотеки C: Многие высокопроизводительные зрелые библиотеки написаны на C/C++. FFI позволяет Rust напрямую использовать их.
  • Системные интерфейсы программирования: Взаимодействовать с возможностями операционной системы, для которых могут существовать только интерфейсы C.
  • Совместимость: Создать библиотеку Rust, которую можно вызывать из других языков (например, Python, Java или JavaScript через Node.js).

Вызов C из Rust: объявление

Чтобы вызвать функцию C из Rust, сначала нужно объявить её сигнатуру с помощью блока extern "C". Это сообщает Rust, как выглядит функция C, не предоставляя её реализацию.

Часть "C" задаёт соглашение о вызовах C, обеспечивая совместимость вызовов функций.

extern "C" {
    // Declare C functions here
    // Example: int puts(const char *s);
    fn puts(s: *const std::os::raw::c_char) -> std::os::raw::c_int;
    // Example: int add(int a, int b);
    fn add(a: std::os::raw::c_int, b: std::os::raw::c_int) -> std::os::raw::c_int;
}

Вызов C из Rust: блок `unsafe`

Главное обещание Rust — безопасность памяти. Однако при взаимодействии с кодом C через FFI Rust не может гарантировать безопасность чужого кода.

Поэтому любой вызов функции C, объявленной в блоке extern "C", необходимо заключать в блок unsafe. Это сигнализирует компилятору и другим разработчикам, что именно Вы отвечаете за соблюдение гарантий безопасности.

extern "C" {
    // We're declaring that a C function `puts` exists.
    fn puts(s: *const std::os::raw::c_char) -> std::os::raw::c_int;
}

fn main() {
    let rust_string = "Hello from Rust via C!";
    // C strings need to be null-terminated.
    let c_string = std::ffi::CString::new(rust_string).expect("CString failed");

    unsafe {
        // Calling the C 'puts' function. This requires 'unsafe'.
        puts(c_string.as_ptr());
    }
    println!("C function call demonstrated.");
}

Сопоставление типов: Rust и C

При использовании FFI необходимо убедиться, что типы Rust корректно соответствуют типам C. Для этого Rust предоставляет специальные типы в std::os::raw и std::ffi.

  • i32 -> std::os::raw::c_int
  • f32 -> std::os::raw::c_float
  • bool -> std::os::raw::c_uchar (или аналогичный тип, поскольку в C нет стандартного логического типа)
  • &str -> *const std::os::raw::c_char (строки C должны завершаться нулевым байтом; обычно это обеспечивается с помощью std::ffi::CString)
  • &mut [T] -> *mut T

Всегда используйте эти явные типы C, чтобы избежать неопределённого поведения.

Пример: вызов функции C `add`

Представим, что у нас есть библиотека C с функцией int add(int a, int b);. Вот как вызвать её из Rust. Обратите внимание на использование c_int для целочисленных типов.

(Этот код демонстрирует синтаксис FFI, но не запустится без скомпилированной библиотеки C, подключённой извне.)

extern "C" {
    // Declaration of the C function `add`
    fn add(a: std::os::raw::c_int, b: std::os::raw::c_int) -> std::os::raw::c_int;
}

fn main() {
    let x = 10;
    let y = 20;

    let result = unsafe {
        // Call the C 'add' function within an unsafe block
        add(x as std::os::raw::c_int, y as std::os::raw::c_int)
    };

    println!("Attempted to call C add. Result (if linked): {}", result);
}

Предоставление Rust для C: основы

Чтобы функцию Rust можно было вызывать из C, нужны две вещи:

  1. #[no_mangle]: этот атрибут не позволяет компилятору Rust изменять имя функции («искажать» его). Компиляторы C ожидают простые имена без искажений.
  2. extern "C": это указывает, что функция должна использовать соглашение о вызовах C, благодаря чему она становится совместимой с C.

Пример: функция Rust для C

Вот функция Rust, которая вычисляет сумму и может вызываться из программы на C. Обратите внимание на атрибуты #[no_mangle] и extern "C".

(Этот код предназначен для компиляции в библиотеку для C, но содержит main для внутреннего тестирования в этой среде.)

#[no_mangle]
pub extern "C" fn rust_add_and_print(
    a: std::os::raw::c_int,
    b: std::os::raw::c_int
) -> std::os::raw::c_int {
    let sum = a + b;
    println!("Rust function received: {} + {} = {}", a, b, sum);
    sum
}

fn main() {
    println!("This Rust code exposes a function for C.");
    // We can also call it internally for demonstration
    let result = rust_add_and_print(5, 7);
    println!("Internal call result: {}", result);
}

Управление памятью в FFI

Управление памятью на границах FFI имеет критическое значение. Если Rust выделяет память (например, для строки) и передаёт указатель в C, C должен либо скопировать данные, либо корректно освободить выделенную память.

И наоборот, если C выделяет память и передаёт указатель в Rust, Rust не должен освобождать её без явного указания; в противном случае необходимо скопировать данные.

Такие средства, как std::ffi::CString и CStr, помогают безопасно работать со строками, совместимыми с C: они обрабатывают завершающий нулевой байт и обеспечивают корректную передачу владения.

Быстрая проверка FFI

Давайте проверим, насколько хорошо Вы поняли интерфейс взаимодействия Rust с внешними функциями.

FFI: мост между мирами

Вы изучили интерфейс взаимодействия Rust с внешними функциями!

FFI превращает Rust в мощный инструмент совместимости и позволяет Вам:

  • вызывать функции из библиотек C с помощью блоков extern "C" и unsafe;
  • предоставлять функции Rust другим языкам с помощью #[no_mangle] и pub extern "C";
  • тщательно сопоставлять типы с помощью типов std::os::raw.

FFI — мощный инструмент для интеграции Rust с различными экосистемами, но помните о важности осторожного использования, особенно при работе с безопасностью и управлением памятью!

Часто задаваемые вопросы

Урок «Интерфейс внешних функций (FFI)» бесплатный?

Да — полный текст урока «Интерфейс внешних функций (FFI)» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 3 уроков всего.

Чему я научусь в уроке «Интерфейс внешних функций (FFI)»?

Научитесь вызывать библиотеки C из Rust и предоставлять функции Rust другим языкам с помощью FFI для обеспечения совместимости. Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Learn Rust Coding?

Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 3.

Сколько времени занимает урок «Интерфейс внешних функций (FFI)»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Learn Rust Coding?

Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Интерфейс внешних функций (FFI)
  2. Rust и WebAssembly (WASM)
  3. Бенчмаркинг и настройка производительности
← Назад к Learn Rust Coding