Creation of a CStr from an &str

Hey all,

With CStr moving to core::ffi, is there a good or recommended way to create one from an &str without going through CString? If not, is there a possibility of adding one? This is quite a common pattern for ffi.

It's a tricky problem because the slice has to be cloned to a buffer that is one larger, so I think any implementation is probably forced to use a const allocated array buffer. I came up with one implementation here using const generics: Rust Playground but I would kind of hope something without an extra struct wrapper would be possible. (A macro may be a better solution, but I can't figure it out).

I'm also somewhat curious how they do it in Rust For Linux, which should probably be about the most official ffi implementation out there.

CStr must have a NUL-terminator, and str won't have it. They're incompatible almost by definition. Your fixed-capacity buffer is probably the best that can be done.

Where are your &str coming from? If it's static, you can include the NUL and peel it away when you don't need it.

That's about what I feared but was hoping I was wrong, I think maybe I'll bring something up on GH since it's a fairly common pattern. Thanks for confirming.

I'm in the process of trying to provide safe abstractions around existing C libraries on bare metal (so CString won't work), so I'm kind of shoehorned into working with unknown &strs coming in and needing to produce CStrs from them.

If you're providing a wrapper around a C API, it doesn't seem unreasonable to just require users to pass CStrs instead of strs. Especially in a context where allocation is impossible.

3 Likes

Incidentally, in your playground, you need from_bytes_until_nul, or your to_cstr will fail due to internal NULs when the buffer isn't sized exactly right. (On stable this probably means scan yourself or store the length...)

You're right that that is a very workable solution, but it kind of suffers from the "bubble up" problem - e.g., if the user of my wrapper gets a &str from some function they call, then this problem of converting to CStr still exists and is just passed on to them.

Nicer IMO to have a user of a FFI wrapper only need to worry about Rust types.

Good catch, just a little toy implementation :slight_smile:

True, but the user of a library has more options than you as the library author do. If the strings are static they can just include the null byte in the original string, for example.

They could also have a simple allocator set up that would make conversion much simpler for them than it would be for you as the library author.

2 Likes

That's a good point too. I just wish there was a better solution for doing this kind of conversion in no_std - there's almost nothing out there that I can find.

I might try to wake up [RFC] A new stack-based vector by c410-f3r · Pull Request #2990 · rust-lang/rfcs · GitHub for this reason, with CStr moving to core it would at least provide a nice option to do the conversion

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.