🧲Rust/심화및 응용

[Rust] Raw-Pointer 직접 관리하는 방법

Mawile 2021. 11. 24.
728x90

Rust

 

안녕하세요!

이번시간에는 Rust에서 C/C++처럼 Raw-Pointer를 프로그래머가 직접 관리하는 방법에 관하여 포스팅하겠습니다.

Rust는 C/C++과는 다르게 프로그래머가 따로 메모리를 관리하지 않아도 알아서 프로그램이 적당히 메모리를 할당하고 할당해제 해줍니다.

 

사실 Rust는 시작한지 몇달됬습니다. Rust관련 포스팅은 귀찮아서 올리지 않고있습니다.

잡담은됬고 바로 시작하겠습니다.

 

 

🥔 Raw-Pointer 직접 관리하는 방법

우선 Rust에서 프로그래머가 Rust컴파일러의 영향을 받지않고 온전히 메모리를 관리하고 싶다면

unsafe

라는 키워드를 사용해야 합니다.

위에서도 설명했다시피 Rust는 이와 같은 예외적인 상황이 아니라면 대부분의 경우 프로그램이 알아서 메모리를 관리해줍니다.

 

다음은 프로그래머가 직접 메모리를 할당/할당해제 하는 방법에 관하여 알아보겠습니다.

🦃 프로그래머가 직접 메모리를 할당/할당해제 하는 방법

Rust에서 동적할당을 프로그램에게 명령하기 위해서는 crate를 사용해야합니다.

 

현재 카르고 프로젝트의 Cargo.toml[dependencies]에다가 다음과 같이 입력해주세요.

[dependencies]
libc = "0.2.108"

이렇게함으로써 c의 일부 라이브러리를 rust로 가져올 수 있습니다.

 

 

🥔 나만의 동적할당/동적할당해제를 이용한 스마트포인터 만들기

우선 rust에서 스마트포인터를 만들기 위해서는 포인터가 할당되어있는지, 실제 포인터가 담긴 구조체를 정의해주어야 합니다.

pub struct MySmartPointer<T> {
    isMalloc: bool,
    ptr: *mut T,
}

isMalloc은 포인터가 할당되어있는지 확인하는 플래그변수입니다.

ptr은 실제 포인터가 들어갈 주소를 저장하는 변수입니다.

 

이제 스마트포인터를 정의하겠습니다.

우선 스마트포인터 기본 객체데이터를 저장할 멤버함수를 추가합니다.

impl<T> MySmartPointer<T> {
    pub fn new() -> MySmartPointer<T> {
        MySmartPointer { isMalloc: false, ptr: std::ptr::null_mut() }
    }

 

이제 메모리주소에 공간을 할당해주는 함수를 정의합니다.

할당받을 "데이터타입의 크기 x 공간길이"를 해주면 우리가 메모리에 할당받을 전체크기가 됩니다.

pub fn alloc(&mut self, size: usize) {
        unsafe {
            if self.isMalloc == false {
                self.isMalloc = true;
                self.ptr = libc::malloc((size * std::mem::size_of::<T>()) as usize) as *mut T;
            }

            return;
        }
    }

 

그리고 메모리주소에 공간을 할당해제해줄 함수도 정의합니다.

pub fn free(&mut self) {
        unsafe {
            if self.isMalloc == true {
                self.isMalloc = false;
                libc::free(self.ptr as *mut libc::c_void);
            }
        }

        return;
    }

 

밑의 소스는 스마트포인터 전체코드입니다.

pub struct MySmartPointer<T> {
    isMalloc: bool,
    ptr: *mut T,
}

impl<T> MySmartPointer<T> {
    pub fn new() -> MySmartPointer<T> {
        MySmartPointer { isMalloc: false, ptr: std::ptr::null_mut() }
    }

    pub fn alloc(&mut self, size: usize) {
        unsafe {
            if self.isMalloc == false {
                self.isMalloc = true;
                self.ptr = libc::malloc((size * std::mem::size_of::<T>()) as usize) as *mut T;
            }

            return;
        }
    }

    pub fn free(&mut self) {
        unsafe {
            if self.isMalloc == true {
                self.isMalloc = false;
                libc::free(self.ptr as *mut libc::c_void);
            }
        }

        return;
    }
}

 

이제 테스트를 해봐야되겠죠?

당연히 raw포인터를 사용할것이기 때문에 main함수도 unsafe로 해줍시다.

 

또, 우리가 실제로 포인터가 작동하는지 알아볼 "change_ptr_val"라는

포인터가 가리키는 메모리의 값을 10만큼 더하는 함수를 정의 해줍시다.

fn change_ptr_val(ptr: *mut i32) {
    unsafe {
        *ptr += 10;
        return;
    }
}

fn main() {
    unsafe {
        let mut MySP = MySmartPointer::<i32>::new();
    
        MySP.alloc(1);
        println!("1: {}", *MySP.ptr);

        *MySP.ptr = 5;
        println!("2: {}", *MySP.ptr);

        change_ptr_val(MySP.ptr);
        println!("3: {}", *MySP.ptr);

        MySP.free();
    }

    return;
}

 

이제 결과값을 확인해봅시다!

결과값

 

와우!! 첫번째는 당연히 값을 주기전이기때문에 쓰레기값이 들어있구요!

첫번째와 세번째도 각각 저의 명령대로 값이 잘 적용되었습니다!

 

 

그럼 오늘은 이만!!

안녕~~!!!

 

 


728x90

'🧲Rust > 심화및 응용' 카테고리의 다른 글

윈도우 생성 Rust Winapi [ Rust GUI Programming ]  (0) 2021.06.03

댓글