Hi!

First of all, if you are writing custom bindings to sqlite not only to
learn Rust, I'd suggest using already existing bindings [1]. That way
you probably won't have to deal with low-level C integration stuff.

However, if you want to learn how to write C bindings, you should
probably start with reading an official tutorial [2] on foreign
function interface. That way you will learn that Rust strings are not
C-compatible, they are not terminated by zero byte, so you can't get a
pointer from a string and pass it to a C routine directly. In order to
properly convert &str to *c_char you have to use various conversion
utilities, the most simple one being with_c_str() method:

    let s = "some_string";
    let result = s.with_c_str(|char_ptr| {
        // call C functions, char_ptr is a *c_char pointer
        // after this block finishes, a buffer pointed to by char_ptr
will be freed
        some_result
    });

Here [3] is the relevant piece of documentation on C strings conversions.

Your second example is also incorrect. Converting C strings to static
slices is highly unsafe, for example, it will crash your program if
the string is not a valid UTF-8 sequence, not to mention lifetime
issues. There is a reason why it is placed in such inconvenient place
as `std::str::raw`. You shouldn't use it. Instead you should use
std::c_str::CString structure to wrap C strings. BTW, this structure
also forces you to think about ownership. I don't know much about
sqlite API, but if you're not supposed to free a string returned by
sqlite3_errmsg() function, you should create CString like this

    CString::new(sqlite3_errmsg(*ppDb), false)

false means that this CString won't own the buffer and won't free it
when it goes out of scope.

When you have CString structure, you can get a string slice out of it
using as_str() method. This all is documented here [4].

    [1]: https://github.com/linuxfood/rustsqlite.
    [2]: http://static.rust-lang.org/doc/master/guide-ffi.html
    [3]: http://static.rust-lang.org/doc/master/std/c_str/index.html
    [4]: http://static.rust-lang.org/doc/master/std/c_str/struct.CString.html

2014-05-10 18:14 GMT+04:00 Christophe Pedretti <christophe.pedre...@gmail.com>:
> Hi all,
>
> i am writing a wrapper to an SQLite database.
>
> If i use :
> extern { fn sqlite3_open(filename: *c_char, ppDb : **mut ()) -> c_int; }
> i can not use :
> let ppDb : **mut () = RawPtr::null();
> unsafe { res=sqlite3_open(filename.as_ptr(), ppDb);
> because as_ptr() returns an *u8 and c_char is a i8, so i have to use
> extern { fn sqlite3_open(filename: *c_uchar, ppDb : **mut ()) -> c_int; }
>
>
> Now, suppose i use :
> extern { fn sqlite3_errmsg(pDb : *mut ()) -> *c_uchar; }
> i can not use :
> let mut desc=""; { unsafe { desc =
> c_str_to_static_slice(sqlite3_errmsg(*ppDb)); } }
> because c_str_to_static_slice taks a *c_char (so an i8) as argument, so i
> have to use
> extern { fn sqlite3_errmsg(pDb : *mut ()) -> *c_char; }
>
> If the second example is quite logical, what about the first one ?
> how to convert &str -> *c_char ?
>
> thanks
>
> --
> Christophe
> http://chris-pe.github.io/Rustic/
>
>
>
>
> _______________________________________________
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to