Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Unsafe 연산

이 섹션을 시작하며 공식 문서의 말을 빌리자면, “코드베이스에서 unsafe 코드의 양을 최소화하도록 노력해야 합니다.” 이 점을 염두에 두고 시작해 봅시다! Rust에서 Unsafe 어노테이션은 컴파일러가 제공하는 보호 기능을 우회하는 데 사용됩니다. 구체적으로, unsafe는 다음과 같은 네 가지 주요 작업에 사용됩니다:

  • raw 포인터 역참조하기
  • unsafe 함수나 메서드 호출하기 (FFI를 통한 함수 호출 포함, 이 책의 이전 장 참조)
  • 정적 가변(static mutable) 변수에 접근하거나 수정하기
  • unsafe 트레이트 구현하기
  • accessing elements of a union

Raw 포인터

Raw 포인터 *와 참조 &T는 비슷하게 작동하지만, 참조는 빌림 검사기(borrow checker) 덕분에 항상 유효한 데이터를 가리킨다는 것이 보장되므로 항상 안전합니다. Raw 포인터의 역참조는 unsafe 블록을 통해서만 수행될 수 있습니다.

fn main() {
    let raw_p: *const u32 = &10;

    unsafe {
        assert!(*raw_p == 10);
    }
}

Unsafe 함수 호출하기

일부 함수는 unsafe로 선언될 수 있는데, 이는 컴파일러 대신 프로그래머가 올바름을 보장해야 할 책임이 있음을 의미합니다. 그 예로 첫 번째 요소에 대한 포인터와 길이를 받아 슬라이스를 생성하는 std::slice::from_raw_parts가 있습니다.

use std::slice;

fn main() {
    let some_vector = vec![1, 2, 3, 4];

    let pointer = some_vector.as_ptr();
    let length = some_vector.len();

    unsafe {
        let my_slice: &[u32] = slice::from_raw_parts(pointer, length);

        assert_eq!(some_vector.as_slice(), my_slice);
    }
}

slice::from_raw_parts의 경우, 반드시 지켜져야 하는 가정 중 하나는 전달된 포인터가 유효한 메모리를 가리키고 가리키는 메모리가 올바른 타입이어야 한다는 것입니다. 이러한 불변성(invariant)이 지켜지지 않으면 프로그램의 동작은 정의되지 않으며 어떤 일이 일어날지 알 수 없습니다.

Union Elements

Elements of unions overlap in memory, thus changing the value of one element automatically changes every element’s value. They can be used, if you don’t know which data type you will need at runtime. Since Rust offers safe Enums, the main purpose of Unions is to allow interacting with C code. Accessing and changing elements of unions is only allowed in unsafe Rust.

union MyFirstUnion {
    float: f32,
    integer: u32
}

fn main() {
    // Creating an object of a union type doesn't require Unsafe Rust.
    let mut u = MyFirstUnion { float: 123.45 };
    
    // Reading and changing u.float or u.integer is only allowed in Unsafe Rust.
    unsafe {
        assert_eq!(u.float, 123.45);
        println!("u.float = 123.45, but u.integer = {}", u.integer);

        u.integer = 42;
        assert_eq!(u.integer, 42);
        println!("u.integer = 42, but u.float = {}", u.float);
    }
}