رفتن به مطلب
  • زمان مطالعه : 4 دقیقه

اگه برنامه‌نویس باشی و با Rust کار کرده باشی، حتما شنیدی که این زبان چقدر رو سرعت و امنیت تمرکز داره. از اون طرف، C هم که یه زبان قدیمی و قدرتمنده و هنوز توی خیلی از پروژه‌ها، مخصوصا پروژه‌های سیستمی، حرف اول رو می‌زنه. حالا فکر کن بخوای این دو تا رو با هم ترکیب کنی! هم قدرت و انعطاف C رو داشته باشی، هم ایمنی و مدرن بودن Rust رو. توی این مطلب می‌خوام بهت نشون بدم چطور می‌تونی Rust و C رو به هم وصل کنی و کدات رو بین این دو تا جابجا کنی.

چرا اصلا Rust و C رو به هم وصل کنیم؟

قبل از اینکه بریم سراغ کد و جزییات، بذار یه لحظه ببینیم چرا این کار منطقیه. Rust یه زبان نسبتا جدیده که خیلی از مشکلات C مثل مدیریت دستی حافظه و خطاهای اشاره‌گر (pointer errors) رو حل کرده. اما خب، C یه اکوسیستم عظیم داره؛ کتابخونه‌هایی مثل POSIX یا حتی کدهای قدیمی پروژه‌ات که نمی‌خوای از صفر با Rust بازنویسی‌شون کنی. اینجا اتصال این دو زبان به کار میاد. می‌تونی از کتابخونه‌های C توی Rust استفاده کنی یا برعکس، کدهای Rust رو توی پروژه‌های C وارد کنی.

مفاهیم اولیه: FFI چیه؟

برای اینکه Rust و C با هم حرف بزنن، از یه چیزی به اسم FFI استفاده می‌کنیم. FFI مخفف "Foreign Function Interface" هست و به زبون ساده، یه جور پل ارتباطی بین زبون‌های مختلفه. توی این مورد، FFI به Rust اجازه می‌ده توابع C رو فراخوانی کنه و برعکس. اما این کار یه سری اصول داره که باید رعایت کنی، چون Rust و C توی مدیریت حافظه و ساختار داده‌ها خیلی فرق دارن.

قدم اول: یه تابع C بنویس

بیا با یه مثال ساده شروع کنیم. فرض کن توی C یه تابع داری که دو تا عدد رو می‌گیره و جمع‌شون می‌کنه:

// math.c
int add(int a, int b) {
    return a + b;
}

برای اینکه Rust بتونه این تابع رو ببینه، باید یه فایل هدر (header) هم بسازی:

// math.h
#ifndef MATH_H
#define MATH_H

int add(int a, int b);

#endif

حالا این فایل C رو کامپایل می‌کنیم تا یه کتابخونه استاتیک بسازیم:

gcc -c math.c -o math.o
ar rcs libmath.a math.o

تا اینجا یه کتابخونه به اسم libmath.a داریم که قراره توی Rust ازش استفاده کنیم.

قدم دوم: اتصال به Rust

توی پروژه Rust، باید به کامپایلر بگی که این کتابخونه خارجی رو لینک کنه. برای این کار از build.rs استفاده می‌کنیم. اگه پروژه‌ات هنوز فایل build.rs نداره، توی ریشه پروژه یه فایل با این اسم بساز و این کد رو توش بذار:

// build.rs
fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rustc-link-lib=math");
    println!("cargo:rustc-link-search=native=.");
}

این کد به Rust می‌گه که کتابخونه libmath.a رو پیدا کنه و به پروژه لینک کنه. یادت باشه فایل libmath.a رو توی همون دایرکتوری پروژه‌ات کپی کنی.

قدم سوم: تعریف تابع در Rust

حالا باید به Rust بگیم که تابع add توی C چه شکلیه. این کار رو با استفاده از بلاک extern "C" انجام می‌دیم. توی فایل main.rs اینجوری می‌نویسی:

// main.rs
extern "C" {
    fn add(a: i32, b: i32) -> i32;
}

fn main() {
    unsafe {
        let result = add(5, 3);
        println!("Result: {}", result);
    }
}

ری می‌کنه که مسئولیت هر مشکلی گردن خودته!

اجرا و تست

حالا کافیه پروژه رو با cargo run اجرا کنی. اگه همه چیز درست پیش بره، خروجی باید این باشه:

Result: 8

تبریک! تونستی یه تابع C رو توی Rust فراخوانی کنی.

برعکسش چطوره؟ Rust به C

حالا فرض کن بخوای یه تابع توی Rust بنویسی و توی C ازش استفاده کنی. بیایم یه مثال بزنیم. توی Rust یه تابع می‌سازیم که یه رشته رو می‌گیره و طولش رو برمی‌گردونه:

// lib.rs
#[no_mangle]
pub extern "C" fn string_length(s: *const i8) -> i32 {
    unsafe {
        let c_str = std::ffi::CStr::from_ptr(s);
        c_str.to_bytes().len() as i32
    }
}

#[no_mangle]به Rust می‌گه اسم تابع رو تغییر نده تا C بتونه پیداش کنه. حالا این پروژه رو به صورت کتابخونه کامپایل می‌کنیم:

cargo build --release

فایل librust.a توی پوشه target/release ساخته می‌شه.

توی C اینجوری ازش استفاده می‌کنیم:

// main.c
#include <stdio.h>
#include <stdint.h>

extern int32_t string_length(const char* s);

int main() {
    const char* text = "Hello from Rust!";
    int32_t len = string_length(text);
    printf("Length: %d\n", len);
    return 0;
}

کامپایلش می‌کنیم:

gcc -L ./target/release -lrust main.c -o test

اگه اجرا کنی، خروجی می‌شه:

Length: 16

نکات مهم و چالش‌ها

اتصال Rust و C خیلی هم ساده نیست. باید حواست به مدیریت حافظه باشه؛ مثلا اگه توی C حافظه تخصیص دادی، Rust انتظار نداره خودش آزادش کنه. یا برعکس، اگه Rust یه چیزی رو آزاد کرد، C نباید دوباره بخواد باهاش کار کنه. یه ابزار خوب برای این کار، استفاده از کتابخونه‌هایی مثل cbindgen و bindgen هست که فایل‌های هدر و تعاریف رو خودکار تولید می‌کنن و کار رو راحت‌تر می‌کنن.

جمع‌بندی

وصل کردن Rust به C یه راه عالیه برای اینکه از بهترین‌های هر دو دنیا استفاده کنی. با FFI و چند خط کد، می‌تونی پروژه‌هات رو قوی‌تر و انعطاف‌پذیرتر کنی.

بازخورد کاربر

دیدگاه‌های پیشنهاد شده

هیچ دیدگاهی برای نمایش وجود دارد.

دیدگاه خود را ارسال کنید

از استفاده از کلمات رکیک و خلاف قوانین و غیر مرتبط با موضوع خودداری کنید ...
توجه: مطلب ارسالی شما پس از تایید مدیریت برای همه قابل رویت خواهد بود.

مهمان
افزودن دیدگاه...