自己解決されたようですがちょっと気になったのでコメントします。
まず、タイトルにある
Rustでリテラルの文字を*mut c_char型する方法
はありません。リテラルの文字列はリードオンリーな領域に確保されるので*mut
には変換できません。無理矢理やれば「型上は」可能ですが、実際に操作しようとするとunsafe
の中で違反を起こすことになります。
解決したとおっしゃってる方法(concat!( "world", "\0")
)は一旦(&'static str
ではなくて)String
に変換しているので先程よりはマシですがこれもmut
でない変数を*mut
に変換しているので問題あります。
Cへ渡す文字(列)へのポインタが欲しいならstd::ffi
にあるCStr
/CString
を使います。また、今回*mut
を使われてますが、書き込みをしないなら*const
を使います。*const u8
ならリテラルの文字列からでもas_ptr
が使えるのであとは自己責任でu8
とc_char
が等しいことを保障すれば欲しい値が手に入るでしょう。
さて、コメントを見るにRustで文字列を確保してGoで利用したいというのがモチベーションのようですが、Rustは所有権でメモリ管理をするので多少工夫しないとdangling pointerかメモリリークかのどちらかを引き起こしてしまいます。最終的にRustに解放を任せてしまえば安全なので以下のようなコードになるでしょうか。
rust
1use std::os::raw::{c_char};
2use std::ffi::{CString, CStr};
3
4
5#[no_mangle]
6pub extern "C" fn echo_rust_string(x: *const c_char) {
7 // ここでは文字列を読むだけなので`*const`で十分ですし、`CStr`で十分です。
8 let x = unsafe { CStr::from_ptr(x).to_str() };
9 let x = x.unwrap();
10 println!("Hello Rust {}", x );
11}
12
13#[no_mangle]
14pub extern "C" fn free_rust_string(x: *mut c_char) {
15 // ここでライフタイムが終わるので文字列が解放される
16 // この文字列は **必ず** `CString`で確保した文字列でないといけない
17 unsafe { CString::from_raw(x) }
18}
19
20
21
22fn main() {
23 println!("hello world");
24 // ここでC向けに文字列を確保する
25 let xin = CString::new( "world");
26 let xin = xin.into_raw();
27 echo_rust_string( xin );
28 free_rust_string(xin);
29}
よく分からないのですが、コメントとここに載せてあるコード上ではこれで良いのですが、リンクを貼ってあるgithubレポジトリ上ではGoで確保したメモリをRustに渡しておられるようなのでそちらであればまた回答は変わります。
Goで確保したメモリならRustで管理はしないので文字列の生成と解放が不要で、このようなコードになるでしょう。
rust
1use std::os::raw::{c_char};
2use std::ffi::{CString, CStr};
3
4
5#[no_mangle]
6pub extern "C" fn echo_rust_string(x: *const c_char) {
7 // ここでは文字列を読むだけなので`*const`で十分ですし、`CStr`で十分です。
8 let x = unsafe { CStr::from_ptr(x).to_str() };
9 let x = x.unwrap();
10 println!("Hello Rust {}", x );
11}
そしてgoで確保した文字列はGoで面倒を看ることになります
go
1package main
2
3/*
4#cgo LDFLAGS: -ldl ./libsample.so ./libsample_rust.so
5#include <stdlib.h>
6#include <dlfcn.h>
7#include "bridge.h"
8*/
9import "C"
10import "unsafe"
11
12func main() {
13 s := C.CString("ねむすぎる")
14 C.echo_rust_string(s)
15 C.free(unsafe.Pointer(s))
16}
今回やりたいことの意図が汲み取れなかったので複数の回答を用意しましたがどれかが参考になれば幸いです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/07/27 03:54