> On Mar 1, 2017, at 7:08 PM, Kenny Leung via swift-users
> <swift-users@swift.org> wrote:
>
> Hi Jordan.
>
> Thanks for the lengthy answer.
>
>> On Mar 1, 2017, at 6:21 PM, Jordan Rose <jordan_r...@apple.com
>> <mailto:jordan_r...@apple.com>> wrote:
>>
>> Hey, Kenny. The const vs non-const part is important, since both the
>> implicit conversion and cString(using:) are allowed to return a pointer to
>> the internal data being used by the String, and modifying that would be
>> breaking the rules (and could potentially cause a crash). In the case of
>> 'fieldSep', it's unlikely that anyone is going to mutate the contents of the
>> string; it was probably just the original author (you?) not bothering to be
>> const-correct. If you control this struct, a better fix would be to use
>> 'const char *' for the field.
>
> This is the PostgreSQL client library, so I don’t really want to change it.
> (Although the source is available. Maybe I should submit a patch…)
>
>> That said, that's not the main isuse. The implicit conversion from String to
>> UnsafePointer<CChar> is only valid when the string is used as a function
>> argument, because the conversion might need to allocate temporary storage.
>> In that case, it’s important to know when it’s safe to deallocate that
>> storage. For a function call, that’s when the call returns, but for storing
>> into a struct field it’s completely unbounded. So there’s no implicit
>> conversion there.
>>
>> If you’re willing to limit your use of the pointer value to a single block
>> of code, you can use withCString
>> <https://developer.apple.com/reference/swift/string/1538904-withcstring>:
>>
>> myString.withCString {
>> var opt :PQprintOpt = PQprintOpt()
>> opt.fieldSep = UnsafeMutablePointer(mutating: $0)
>> // use 'opt'
>> }
>
> Unfortunately, this is not always an option, since there are multiple char *
> files in PQprintOpt. Or could I just nest .withCString calls? Looks ugly, but
> might work, I guess.
Here are some basic recommendations for converting between String and C string
representations:
https://swift.org/migration-guide/se-0107-migrate.html#common-use-cases
The best ways to convert Swift to C strings are:
1. Pass the Swift string as a function argument of type
Unsafe[Mutable]Pointer<Int8>.
2. Use `String.withCString` to create a block of Swift code that can
access the C string.
That doesn't help you if you want to store a pointer to the CString in a
property without defining its scope. In that case, you just need to explicitly
copy the string.
I like Jordan's recommendation for calling strdup. That's the canonical way of
creating a new C string with its own lifetime.
Guillaume's explanation with withMemoryRebound(to:) is also correct, if you
want to work at that level.
We probably should provide an API that handles the special case of String
literals so you don't need to copy. As Jordan suggested, that we could simply
add a `cstring` property to StaticString. Feel free to file a bug for that so
it isn't forgotten.
-Andy
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users