[Rust 공식문서 한국어 정리] ㉒. Rust 외부 함수 인터페이스(FFI) 가이드
[Rust 공식문서 한국어 정리] ㉒. Rust 외부 함수 인터페이스(FFI) 가이드
원문 제목: FFI — The Rustonomicon
작성자: The Rust Language Team
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📌 1. 서론 — 이 문서가 다루는 내용
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
이 문서는 Rust가 다른 언어, 특히 C와 상호작용하는 FFI(Foreign Function Interface) 메커니즘을 심층적으로 다룹니다.
안전한 Rust 경계를 넘어 unsafe 영역에서 외부 코드를 호출하거나 외부에 노출하는 방법을 설명합니다.
ABI 호환성, 타입 매핑, 콜백 패턴, 그리고 FFI에서 흔히 발생하는 메모리 안전성 문제를 중심으로 설명합니다.
Rust의 소유권 모델과 C의 수동 메모리 관리가 충돌하는 지점에서 어떻게 버그를 방지할 수 있는지를 핵심 주제로 삼습니다.
시스템 통합, 라이브러리 래핑, 플랫폼 API 호출을 하는 Rust 개발자에게 필수적인 내용입니다.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔑 2. 핵심 개념 4가지
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
① extern 키워드: 외부 함수를 선언하거나 Rust 함수를 C ABI로 노출할 때 사용합니다.
② #[repr(C)]: Rust 구조체와 열거형이 C의 메모리 레이아웃을 따륵도록 강제합니다.
③ unsafe 블록: FFI 호출은 컴파일러가 보증할 수 없는 외부 행동을 내포하므로 unsafe로 감싸야 합니다.
④ Send/Sync 경계: 외부에서 받은 raw 포인터가 스레드边으로 전달될 때 안전성을 명시적으로 검증해야 합니다.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📖 3. 주요 내용 상세
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FFI의 기본은 extern "C" 블록을 사용해 외부 함수를 선언하는 것입니다.
extern "C" { fn abs(x: c_int) -> c_int; } 와 같이 C 표준 라이브러리 함수를 Rust에서 직접 호출할 수 있습니다.
반대로 Rust 함수에 #[no_mangle]과 pub extern "C"를 붙이면 C 코드에서 해당 함수를 찾아 호출할 수 있습니다.
타입 매핑은 std::os::raw와 libc 크레이트를 통해 표준화되어 있습니다.
c_int, c_char, c_void, c_ulong 등의 타입은 플랫폼에 따라 크기가 달라질 수 있으므로, 고정폭 타입(i32, u64 등) 대신 이를 사용해야 호환성이 보장됩니다.
포인터는 *const T와 *mut T로 표현하며, 참조(&T, &mut T)와 달리 수명과 null 안전성을 보증하지 않습니다.
구조체를 FFI에 노출할 때는 #[repr(C)]를 반드시 지정해야 합니다.
Rust의 기본 레이아웃은 최적화를 위해 정의되지 않은(undefined) 패딩과 정렬을 가질 수 있습니다.
#[repr(C)]는 C 컴파일러와 동일한 필드 순서와 정렬 규칙을 적용하여 바이너리 호환성을 확보합니다.
콜백 패턴은 외부 라이브러리가 Rust 함수를 역으로 호출할 때 사용됩니다.
extern "C" fn callback(x: c_int) 형태로 정의하고, 외부 함수에 함수 포인터를 전달합니다.
이때 클로저는 직접 전달할 수 없으므로, 필요한 경우 사용자 데이터(void*)에 캡슐화합니다.
메모리 안전성은 FFI에서 가장 어려운 부분입니다.
C가 반환한 포인터가 dangling인지, 버퍼 크기가 일치하는지, 문자열 인코딩이 UTF-8인지 등을 Rust가 보증할 수 없습니다.
따라서 FFI 경계에서 raw 포인터를 안전한 래퍼로 변환할 때, 모든 전제조건을 assert하고, Option<NonNull<T>> 등으로 null을 명시적으로 처리합니다.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🛠 4. 실전 활용
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OS API(System Call), OpenGL, Vulkan, WinAPI 등을 Rust에서 직접 호출할 때 FFI를 사용합니다.
unsafe 블록을 최소화하고, sys 크레이트로 raw 바인딩을 분리한 뒤 상위에서 safe 래퍼를 제공합니다.
bindgen이나 cxx로 자동 바인딩을 생성하여 수동 선언의 오류를 줄입니다.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ 5. 정리
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FFI는 Rust의 안전한 세계와 외부 생태계를 연결하는 다리입니다.
extern, #[repr(C)], unsafe의 조합을 정확히 이해하고, 메모리 안전성 가정을 명시적으로 검증해야 합니다.
가능하다면 자동 바인딩 도구를 활용하고, 수동 FFI는 최소한의 경계에서만 다루는 것이 바람직합니다.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔗 출처 링크
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
원문: https://doc.rust-lang.org/nomicon/ffi.html
Rustonomicon: https://doc.rust-lang.org/nomicon/
#Rust #FFI #C #Unsafe #Interop #SystemsProgramming #번역

오뉴노노 님의 최근 댓글
ㅋㅋㅋㅋㅋ 2019 01.14 잘 읽었습니다 2018 12.30 포인트가 없어서 아직 시작을 못하고있는데요! 글은 잘 읽었습니다! 포인트 쌓고 도전할거에요 2018 12.30