I noticed some unusual behaviour when working with a C library which took strings in as const char *
(which is converted to Swift as UnsafePointer<Int8>!
); passing a String
worked as expected, but a String?
seemed to corrupt the input. Consider the test I wrote:
func test(_ input: UnsafePointer<UInt8>?) {
if let string = input {
print(string[0], string[1], string[2], string[3], string[4], string[5])
} else {
print("nil")
}
}
let input: String = "Hello"
test(input)
This works as expected, printing a null-terminated list of UTF-8 bytes for the input string: 72 101 108 108 111 0
However, if I change the input to an optional string, so that it becomes:
let input: String? = "Hello"
I get a completely different set of values in the result (176 39 78 23 1 0
), even though I would expect it to be the same. Passing in nil
works as expected.
The C library's function allows NULL
in place of a string, and I sometimes want to pass that in in Swift as well, so it makes sense for the input string to be an optional.
Is this a bug in Swift, or was Swift not designed to handle this case? Either way, what's the best way to handle this case?
Edit
It appears to have something to do with multiple arguments. The C function:
void multiString(const char *arg0, const char *arg1, const char *arg2, const char *arg3) {
printf("%p: %c %c %c\n", arg0, arg0[0], arg0[1], arg0[2]);
printf("%p: %c %c %c\n", arg1, arg1[0], arg1[1], arg1[2]);
printf("%p: %c %c %c\n", arg2, arg2[0], arg2[1], arg2[2]);
printf("%p: %c %c %c\n", arg3, arg3[0], arg3[1], arg3[2]);
}
Swift:
let input0: String? = "Zero"
let input1: String? = "One"
let input2: String? = "Two"
let input3: String? = "Three"
multiString(input0, input1, input2, input3)
Results in:
0x101003170: T h r
0x101003170: T h r
0x101003170: T h r
0x101003170: T h r
It appears that there's a bug with how Swift handles multiple arguments.