Problems

Problem 1

Here's an easy one to get you started. It contains a Rust library:


# #![allow(unused_variables)]
#fn main() {
// adder.rs

pub extern "C" fn add(a: u32, b: u32) -> u32 {
    a + b
}
#}

And a C/C++ program which uses it.

// main.cpp

#include <iostream>
#include <cstdint>

extern "C" {
    uint32_t add(uit32_t, uit32_t);
}

int main() {
    uint32_t a = 5, b = 10;

    uint32_t sum = add(a, b);
    std::cout << "The sum of " << a 
              << " and " << b 
              << " is " << sum 
              << std::endl;
}

Building and running:

$ rustc --crate-type cdylib adder.rs
$ clang++ -std=c++14 -c main.cpp
$ clang++ -std=c++14 -o main -L. -ladder main.o
$ ./main

Problem 2

This problem is similar to the previous one in that it has a Rust library called by a C++ program.


# #![allow(unused_variables)]
#fn main() {
// foo.rs

#[no_mangle]
pub extern "C" fn foo() {
    panic!("Oops...");
}
#}

The main program:

// main.cpp

extern "C" {
    void foo();
}

int main() {
    foo();
}

Compiling and running is also pretty similar:

$ rustc --crate-type cdylib foo.rs
$ clang++ -std=c++14 -c main.cpp
$ clang++ -std=c++14 -o main -L. -lfoo main.o
$ ./main

Problem 3


# #![allow(unused_variables)]
#fn main() {
// home.rs

use std::ffi::CString;
use std::env;
use std::ptr;
use std::os::c_char;


#[no_mangle]
pub extern "C" fn home_directory() -> *const c_char {
    let home = match env::home_dir() {
        Some(p) => p,
        None => return ptr::null(),
    };

    let c_string = match CString::new(home){
        Ok(s) => s,
        Err(_) => return ptr::null(),
    };

    c_string.as_ptr()
}
#}
// main.cpp

#include <iostream>

extern "C" {
    char *home_directory();
}

int main() {
    char* home = home_directory();

    if (home == nullptr) {
        std::cout << "Unable to find the home directory" << std::endl;
    } else {
        std::cout << "Home directory is " << home << std::endl; 
    }
}

Compiling and running:

$ rustc --crate-type cdylib home.rs
$ clang++ -std=c++14 -c main.cpp
$ clang++ -std=c++14 -o main -L. -lhome main.o
$ ./main

Problem 4


# #![allow(unused_variables)]
#fn main() {
// logging.rs

use std::os::raw::c_char;
use std::ffi::CStr;


#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(C)]
pub enum LogLevel {
    Off = 0x00,
    Error = 0x01,
    Warn = 0x02,
    Info = 0x04,
    Debug = 0x08,
    Trace = 0x0a,
}

#[no_mangle]
pub unsafe extern "C" fn log_message(level: LogLevel, message: *const c_char) {
    if level == LogLevel::Off {
        return;
    }

    let message = CStr::from_ptr(message);
    eprintln!("{:?}: {}", level, message.to_string_lossy());
}
#}
// main.cpp

#include <iostream>
#include <string>

extern "C" {
void log_message(int, const char *);
}

int main() {
  std::string message = "Hello World";
  log_message(0x04 | 0x01, message.c_str());
}