String value to UnsafePointer<UInt8> function parameter behavior - swift

I found the following code compiles and works:
func foo(p:UnsafePointer<UInt8>) {
var p = p
for p; p.memory != 0; p++ {
print(String(format:"%2X", p.memory))
}
}
let str:String = "今日"
foo(str)
This prints E4BB8AE697A5 and that is a valid UTF8 representation of 今日
As far as I know, this is undocumented behavior. from the document:
When a function is declared as taking a UnsafePointer argument, it can accept any of the following:
nil, which is passed as a null pointer
An UnsafePointer, UnsafeMutablePointer, or AutoreleasingUnsafeMutablePointer value, which is converted to UnsafePointer if necessary
An in-out expression whose operand is an lvalue of type Type, which is passed as the address of the lvalue
A [Type] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call
In this case, str is non of them.
Am I missing something?
ADDED:
And it doesn't work if the parameter type is UnsafePointer<UInt16>
func foo(p:UnsafePointer<UInt16>) {
var p = p
for p; p.memory != 0; p++ {
print(String(format:"%4X", p.memory))
}
}
let str:String = "今日"
foo(str)
// ^ 'String' is not convertible to 'UnsafePointer<UInt16>'
Even though the internal String representation is UTF16
let str = "今日"
var p = UnsafePointer<UInt16>(str._core._baseAddress)
for p; p.memory != 0; p++ {
print(String(format:"%4X", p.memory)) // prints 4ECA65E5 which is UTF16 今日
}

This is working because of one of the interoperability changes the Swift team has made since the initial launch - you're right that it looks like it hasn't made it into the documentation yet. String works where an UnsafePointer<UInt8> is required so that you can call C functions that expect a const char * parameter without a lot of extra work.
Look at the C function strlen, defined in "shims.h":
size_t strlen(const char *s);
In Swift it comes through as this:
func strlen(s: UnsafePointer<Int8>) -> UInt
Which can be called with a String with no additional work:
let str = "Hi."
strlen(str)
// 3
Look at the revisions on this answer to see how C-string interop has changed over time: https://stackoverflow.com/a/24438698/59541

Related

Is Swift's handling of CVarArg for String buggy?

While writing a Swift wrapper for a C wrapper of a C++ library, I've stumbled on some weird bugs regarding Swift's CVarArg. The C wrapper I already have uses variadic functions which I converted to functions using va_list as an argument so they could be imported (since Swift cannot import C variadic functions). When passing arguments to such a function, once bridged to Swift, it uses the private _cVarArgEncoding property of types conforming to CVarArg to "encode" the values which are then sent as a pointer to the C function. It seems however that this encoding is faulty for Swift Strings.
To demonstrate, I've created the following package:
Package.swift
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "CVarArgTest",
products: [
.executable(
name: "CVarArgTest",
targets: ["CVarArgTest"]),
],
targets: [
.target(
name: "CLib"),
.target(
name: "CVarArgTest",
dependencies: ["CLib"])
]
)
CLib
CTest.h
#ifndef CTest_h
#define CTest_h
#include <stdio.h>
/// Prints out the strings provided in args
/// #param num The number of strings in `args`
/// #param args A `va_list` of strings
void test_va_arg_str(int num, va_list args);
/// Prints out the integers provided in args
/// #param num The number of integers in `args`
/// #param args A `va_list` of integers
void test_va_arg_int(int num, va_list args);
/// Just prints the string
/// #param str The string
void test_str_print(const char * str);
#endif /* CTest_h */
CTest.c
#include "CTest.h"
#include <stdarg.h>
void test_va_arg_str(int num, va_list args)
{
printf("Printing %i strings...\n", num);
for (int i = 0; i < num; i++) {
const char * str = va_arg(args, const char *);
puts(str);
}
}
void test_va_arg_int(int num, va_list args)
{
printf("Printing %i integers...\n", num);
for (int i = 0; i < num; i++) {
int foo = va_arg(args, int);
printf("%i\n", foo);
}
}
void test_str_print(const char * str)
{
puts(str);
}
main.swift
import Foundation
import CLib
// The literal String is perfectly bridged to the CChar pointer expected by the function
test_str_print("Hello, World!")
// Prints the integers as expected
let argsInt: [CVarArg] = [123, 456, 789]
withVaList(argsInt) { listPtr in
test_va_arg_int(Int32(argsInt.count), listPtr)
}
// ERROR: Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
let argsStr: [CVarArg] = ["Test", "Testing", "The test"]
withVaList(argsStr) { listPtr in
test_va_arg_str(Int32(argsStr.count), listPtr)
}
The package is available here as well.
As commented in the code above, printing a String via C or a va_list containing Ints works as expected, but when converted to const char *, there's an exception (EXC_BAD_ACCESS (code=EXC_I386_GPFLT)).
So, in short: did I mess up the C side of it or is Swift doing something wrong here? I've tested this in Xcode 11.5 and 12.0b2. If it's a bug, I'll be happy to report it.
This one's a bit tricky: your string is actually being bridged to an Objective-C NSString * rather than a C char *:
(lldb) p str
(const char *) $0 = 0x3cbe9f4c5d32b745 ""
(lldb) p (id)str
(NSTaggedPointerString *) $1 = 0x3cbe9f4c5d32b745 #"Test"
(If you're wondering why it's an NSTaggedPointerString rather than just an NSString, this article is a great read -- in short, the string is short enough to be stored directly in the bytes of the pointer variable rather than in an object on the heap.
Looking at the source code for withVaList, we see that a type's va_list representation is determined by its implementation of the _cVarArgEncoding property of the CVarArg protocol. The standard library has some implementations of this protocol for some basic integer and pointer types, but there's nothing for String here. So who's converting our string to an NSString?
Searching around the Swift repo on GitHub, we find that Foundation is the culprit:
//===----------------------------------------------------------------------===//
// CVarArg for bridged types
//===----------------------------------------------------------------------===//
extension CVarArg where Self: _ObjectiveCBridgeable {
/// Default implementation for bridgeable types.
public var _cVarArgEncoding: [Int] {
let object = self._bridgeToObjectiveC()
_autorelease(object)
return _encodeBitsAsWords(object)
}
}
In plain English: any object which can be bridged to Objective-C is encoded as a vararg by converting to an Objective-C object and encoding a pointer to that object. C varargs are not type-safe, so your test_va_arg_str just assumes it's a char* and passes it to puts, which crashes.
So is this a bug? I don't think so -- I suppose this behavior is probably intentional for compatibility with functions like NSLog that are more commonly used with Objective-C objects than C ones. However, it's certainly a surprising pitfall, and it's probably one of the reasons why Swift doesn't like to let you call C variadic functions.
You'll want to work around this by manually converting your strings to C-strings. This can get a bit ugly if you have an array of strings that you want to convert without making unnecessary copies, but here's a function that should be able to do it.
extension Collection where Element == String {
/// Converts an array of strings to an array of C strings, without copying.
func withCStrings<R>(_ body: ([UnsafePointer<CChar>]) throws -> R) rethrows -> R {
return try withCStrings(head: [], body: body)
}
// Recursively call withCString on each of the strings.
private func withCStrings<R>(head: [UnsafePointer<CChar>],
body: ([UnsafePointer<CChar>]) throws -> R) rethrows -> R {
if let next = self.first {
// Get a C string, add it to the result array, and recurse on the remainder of the collection
return try next.withCString { cString in
var head = head
head.append(cString)
return try dropFirst().withCStrings(head: head, body: body)
}
} else {
// Base case: no more strings; call the body closure with the array we've built
return try body(head)
}
}
}
func withVaListOfCStrings<R>(_ args: [String], body: (CVaListPointer) -> R) -> R {
return args.withCStrings { cStrings in
withVaList(cStrings, body)
}
}
let argsStr: [String] = ["Test", "Testing", "The test"]
withVaListOfCStrings(argsStr) { listPtr in
test_va_arg_str(Int32(argsStr.count), listPtr)
}
// Output:
// Printing 3 strings...
// Test
// Testing
// The test

Why converting Double to Int doesn't return optional Int in Swift?

Converting a String to Int returns an optional value but converting a Double to Int does not return an optional value. Why is that? I wanted to check if a double value is bigger than maximum Int value, but because converting function does not return an optional value, I am not be able to check by using optional binding.
var stringNumber: String = "555"
var intValue = Int(stringNumber) // returns optional(555)
var doubleNumber: Double = 555
var fromDoubleToInt = Int(doubleNumber) // returns 555
So if I try to convert a double number bigger than maximum Integer, it crashes instead of returning nil.
var doubleNumber: Double = 55555555555555555555
var fromDoubleToInt = Int(doubleNumber) // Crashes here
I know that there's another way to check if a double number is bigger than maximum Integer value, but I'm curious as why it's happening this way.
If we consider that for most doubles, a conversion to Int simply means dropping the decimal part:
let pieInt = Int(3.14159) // 3
Then the only case in which the Int(Double) constructor returns nil is in the case of an overflow.
With strings, converting to Int returns an optional, because generally, strings, such as "Hello world!" cannot be represented as an Int in a way that universally makes sense. So we return nil in the case that the string cannot be represented as an integer. This includes, by the way, values that can be perfectly represented as doubles or floats:
Consider:
let iPi = Int("3.14159")
let dPi = Double("3.14159")
In this case, iPi is nil while dPi is 3.14159. Why? Because "3.14159" doesn't have a valid Int representation.
But meanwhile, when we use the Int constructor which takes a Double and returns non-optional, we get a value.
So, if that constructor is changed to return an optional, why would it return 3 for 3.14159 instead of nil? 3.14159 can't be represented as an integer.
But if you want a method that returns an optional Int, returning nil when the Double would overflow, you can just write that method.
extension Double {
func toInt() -> Int? {
let minInt = Double(Int.min)
let maxInt = Double(Int.max)
guard case minInt ... maxInt = self else {
return nil
}
return Int(self)
}
}
let a = 3.14159.toInt() // returns 3
let b = 555555555555555555555.5.toInt() // returns nil
Failable initializers and methods with Optional return types are designed for scenarios where you, the programmer, can't know whether a parameter value will cause failure, or where verifying that an operation will succeed is equivalent to performing the operation:
let intFromString = Int(someString)
let valueFromDict = dict[someKey]
Parsing an integer from a string requires checking the string for numeric/non-numeric characters, so the check is the same as the work. Likewise, checking a dictionary for the existence of a key is the same as looking up the value for the key.
By contrast, certain operations are things where you, the programmer, need to verify upfront that your parameters or preconditions meet expectations:
let foo = someArray[index]
let bar = UInt32(someUInt64)
let baz: UInt = someUInt - anotherUInt
You can — and in most cases should — test at runtime whether index < someArray.count and someUInt64 < UInt32.max and someUInt > anotherUInt. These assumptions are fundamental to working with those kinds of types. On the one hand, you really want to design around them from the start. On the other, you don't want every bit of math you do to be peppered with Optional unwrapping — that's why we have types whose axioms are stated upfront.

How to create a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

I'm working with a C API from Swift and for one of the methods that I need to call I need to give a
UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
More Info:
Swift Interface:
public func presage_predict(prsg: presage_t, _ result: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>) -> presage_error_code_t
Original C:
presage_error_code_t presage_predict(presage_t prsg, char*** result);
Generally, if a function takes a UnsafePointer<T> parameter
then you can pass a variable of type T as in "inout" parameter with &. In your case, T is
UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
which is the Swift mapping of char **. So you can call the C function
as
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK { ... }
From the documentation and sample code of the Presage library I
understand that this allocates an array of strings and assigns the
address of this array to the variable pointed to by prediction.
To avoid a memory leak, these strings have to be released eventually
with
presage_free_string_array(prediction)
To demonstrate that this actually works, I have taken the first
part of the demo code at presage_c_demo.c and translated it
to Swift:
// Duplicate the C strings to avoid premature deallocation:
let past = strdup("did you not sa")
let future = strdup("")
func get_past_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(past)
}
func get_future_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(future)
}
var prsg = presage_t()
presage_new(get_past_stream, nil, get_future_stream, nil, &prsg)
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK {
for var i = 0; prediction[i] != nil; i++ {
// Convert C string to Swift `String`:
let pred = String.fromCString(prediction[i])!
print ("prediction[\(i)]: \(pred)")
}
presage_free_string_array(prediction)
}
free(past)
free(future)
This actually worked and produced the output
prediction[0]: say
prediction[1]: said
prediction[2]: savages
prediction[3]: saw
prediction[4]: sat
prediction[5]: same
There may be a better way but this runs in playground and defines a value r with the type you want:
func ptrFromAddress<T>(p:UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T>
{
return p
}
var myInt:Int8 = 0
var p = ptrFromAddress(&myInt)
var q = ptrFromAddress(&p)
var r = ptrFromAddress(&q)
What's the point of defining ptrFromAddress, which seems like it does nothing? My thinking is that the section of the Swift interop book which discusses mutable pointers shows many ways to initialize them by passing some expression as an argument (like &x), but does not seem to show corresponding ways where you simply call UnsafeMutablePointer's initializer. So let's define a no-op function just to use those special initialization methods based on argument-passing
Update:
While I believe the method above is correct, it was pointed out by #alisoftware in another forum that this seems to be a safer and more idiomatic way to do the same thing:
var myInt: Int8 = 0
withUnsafeMutablePointer(&myInt) { (var p) in
withUnsafeMutablePointer(&p) { (var pp) in
withUnsafeMutablePointer(&pp) { (var ppp) in
// Do stuff with ppp which is a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
}
}
}
It's more idiomatic because you're using the function withUnsafeMutablePointer which is supplied by the Swift standard library, rather than defining your own helper. It's safer because you are guaranteed that the UnsafeMutablePointer is only alive during the extent of the call to the closure (so long as the closure itself does not store the pointer).

Swift convert string to UnsafeMutablePointer<Int8>

I have a C function mapped to Swift defined as:
func swe_set_eph_path(path: UnsafeMutablePointer<Int8>) -> Void
I am trying to pass a path to the function and have tried:
var path = [Int8](count: 1024, repeatedValue: 0);
for i in 0...NSBundle.mainBundle().bundlePath.lengthOfBytesUsingEncoding(NSUTF16StringEncoding)-1
{
var range = i..<i+1
path[i] = String.toInt(NSBundle.mainBundle().bundlePath[range])
}
println("\(path)")
swe_set_ephe_path(&path)
but on the path[i] line I get the error:
'subscript' is unavailable: cannot subscript String with a range of
Int
swe_set_ephe_path(NSBundle.mainBundle().bundlePath)
nor
swe_set_ephe_path(&NSBundle.mainBundle().bundlePath)
don't work either
Besides not working, I feel there has got to be a better, less convoluted way of doing this. Previous answers on StackOverflow using CString don't seem to work anymore. Any suggestions?
Previous answers on StackOverflow using CString don't seem to work anymore
Nevertheless, UnsafePointer<Int8> is a C string. If your context absolutely requires an UnsafeMutablePointer, just coerce, like this:
let s = NSBundle.mainBundle().bundlePath
let cs = (s as NSString).UTF8String
var buffer = UnsafeMutablePointer<Int8>(cs)
swe_set_ephe_path(buffer)
Of course I don't have your swe_set_ephe_path, but it works fine in my testing when it is stubbed like this:
func swe_set_ephe_path(path: UnsafeMutablePointer<Int8>) {
println(String.fromCString(path))
}
In current version of Swift language you can do it like this (other answers are outdated):
let path = Bundle.main.bundlePath
let param = UnsafeMutablePointer<Int8>(mutating: (path as NSString).utf8String)
It’s actually extremely irritating of the library you’re using that it requires (in the C declaration) a char * path rather than const char * path. (this is assuming the function doesn’t mutate the input string – if it does, you’re in a whole different situation).
If it didn’t, the function would come over to Swift as:
// note, UnsafePointer not UnsafeMutablePointer
func swe_set_eph_path(path: UnsafePointer<Int8>) -> Void
and you could then rely on Swift’s implicit conversion:
let str = "blah"
swe_set_eph_path(str) // Swift implicitly converts Strings
// to const C strings when calling C funcs
But you can do an unsafe conversion quite easily, in combination with the withCString function:
str.withCString { cstr in
swe_set_eph_path(UnsafeMutablePointer(cstr))
}
I had a static library (someLibrary.a) written in C++ compiled for iOS.
The header file (someLibrary.h) had a function exposed like this:
extern long someFunction(char* aString);
The declaration in Swift looks like this:
Int someFunction(aString: UnsafeMutablePointer<Int8>)
I made an extension to String:
extension String {
var UTF8CString: UnsafeMutablePointer<Int8> {
return UnsafeMutablePointer((self as NSString).UTF8String)
}
}
So then I can call the method like so:
someFunction(mySwiftString.UTF8CString)
Update: Make String extension (swift 5.7)
extension String {
var UTF8CString: UnsafeMutablePointer<Int8> {
return UnsafeMutablePointer(mutating: (self as NSString).utf8String!)
}
}

'SKNode!' is not a subtype of 'SKNode'

I can't figure out why I am getting this error on the last line: 'SKNode!' is not a subtype of 'SKNode'
func move_background(){
let enumerationBlock: (SKNode, CMutablePointer<ObjCBool>) -> Void = { bg, stop in
var bg_velocity = CGPointMake(0,CGFloat(-self.bg_velocity))
var distance_to_move = self.point_multiply_scalar(bg_velocity, b: self.dt!)
bg.position = self.point_add(bg.position, b: distance_to_move)
if bg.position.y <= -bg.frame.height {
bg.position = CGPointMake(bg.position.x, bg.position.y + bg.frame.height * 2)
}
}
self.enumerateChildNodesWithName("bg", usingBlock: enumerationBlock)
}
Can any of you help me out?
In the SKNode class, the block argument to this message is of the type (void (^)(SKNode *node, BOOL *stop))
When Swift imports an Objective-C class, all of its message arguments and return values are imported as optionals -- arguments you pass to functions are always NSString? or NDSData?, not just NSString or NSData. They do this because all pointers in Obj-C can be nil, but a var in Swift can't be nil unless it has a question mark at the end, thus making it an "optional" type.
So when you define your enmuerationBlock, it should be of the type
(SKNode?, CMutablePointer<ObjCBool>) -> Void
EDIT answering flainez's question below:
When you have a mutable pointer, you dereference it by obtaining an UnsafePointer thus
var val :CMutablePointer<Bool> = /* get this from somewhere */
val.withUnsafePointer() { (p :UnsafePointer<Bool>) in
p.memory = true /* or whatever */
}
.withUnsafePointer yields an UnsafePointer<T> to the block, and UnsafePointer<T> has a memory property that is assignable.
Annoying: You can't test this in the Playground's REPL, it always fails, but it works when you compile it to a proper target.