How to pass substring from Swift to C? - swift

I have the variable with the value "7438754876*567".I have got this from string as substring.I want to pass this value to c function.
void getRechargePinFromDestination(char* rechargeNumber)
{
setRechargeValue(rechargeNumber);
}
As I have declared as char, swift takes it as a Int8.How can I pass this value.Anyone please help me.Thanks in advance.

If the C function does not mutate the passed string then you should declare the argument as a const char*:
void getRechargePinFromDestination(const char* rechargeNumber)
{
// ...
}
Now you can pass Swift substrings by converting them to a String first (which is automatically converted to a temporary C string):
getRechargePinFromDestination(String(subString))
or with
subString.withCString { getRechargePinFromDestination($0) }
In either case, the C function is called with a pointer to a temporary C string representation, which is only valid during the function call.

Related

Argument `#1' cannot convert `string' expression to type `char[]'

The best overloaded method match for `string.Split(params char[])' has some invalid arguments
Argument `#1' cannot convert `string' expression to type `char[]'
I'm trying to make a Text Dialogue but this error prevents me from compiling. What's wrong?
public TextAsset textFile;
public string[] textLines;
// Use this for initialization
void Start() {
if (textFile != null)
{
textLines = (textFile.text.Split("\n"));
}
}
string.Split has a couple of different overloads (combinations of parameters it can take), but none of them take a single string parameter. "\n" is a string literal, so it's an invalid argument.
One of the overloads takes a params char[], meaning you can either pass an array of chars, or you can just pass a bunch of individual chars and it will make the array for you. So you can use test.Split('\n') because single quotes ' denote a char literal rather than a string literal.

pass a swift var to a C api as void**

I have a C api that looks as follows
struct foo_private_t;
typedef foo_private_t* foo_t;
void foo_func(void**x);
Where the API is intended to be used like this
foo_t x;
void foo_func((void**) &x);
Why the API takes a void** and not a foo_t* is beyond the scope of this question. The problem is when I try to call this API from swift. First I import the C header into swift via the bridging header. Then I try to invoke foo_func with a pointer to a swift object.
var x:foo_t?
foo_func(&x)
// error is cannot convert value of type 'foo_t?' (aka 'Optional<OpaquePointer>') to expected argument type 'UnsafeMutableRawPointer?'
That error is expected, I need a pointer to the pointer, so I tried.
withUnsafeMutablePointer(to: x){ x_p in foo_func(x_p) }
// error is cannot convert value of type 'UnsafeMutablePointer<_>' to expected argument type 'UnsafeMutablePointer<UnsafeMutableRawPointer?>!'
This also seems reasonable as x_p is similar to &x, a single level of pointerness. The next attempt I would have expected to work.
withUnsafeMutablePointer(to: x){ x_p in foo_func(&x_p) }
// error is cannot pass immutable value of type 'UnsafeMutableRawPointer?' as inout argument
Searching around for this error reveals that if I was calling a swift function I should use the inout modifier to a parameter. But since I am calling a C api I am not sure that I can make such a modification. How can I pass a pointer that is a mutable value?
If the intention is to pass the address of x to the C function
in a way that foo_func() can assign a new value to x (which
is what the C code
foo_t x;
void foo_func((void**) &x);
does) then it would be:
var x: foo_t?
withUnsafeMutablePointer(to: &x) {
$0.withMemoryRebound(to: UnsafeMutableRawPointer?.self, capacity: 1) {
foo_func($0)
}
}
Inside withUnsafeMutablePointer(), $0 is a
UnsafeMutablePointer<foo_t?>
and this is rebound to a pointer of the expected type
UnsafeMutablePointer<UnsafeMutableRawPointer?>
I was able to get this to work.
var e = UnsafeMutableRawPointer(x)
foo_func(&e)
x is already a pointer, so it can be converted to a raw pointer. Then I need a pointer to that raw pointer, so I take the address of e. I guess I need the e variable because an implicit temporary value cannot be passed as an argument to an inout parameter. E.g.
foo_func(&UnsafeMutableRawPointer(x))
// error is cannot convert value of type 'foo_t?' (aka 'Optional<OpaquePointer>') to expected argument type 'UnsafeMutableRawPointer?'

Weird issues when passing an array of structs from Swift to C

I'm passing an array of structs from Swift to a C function. The struct looks like this:
struct Struct {
int a;
float b;
float c;
const char* d;
const char* e;
const char* f;
const char* g;
int h[4];
};
Function signature of the C function:
void test(struct Struct* structs);
Weirdly, when I print d in the C function, it's often something different than what I set it to in the Swift code: usually an empty string or some garbage. When I set d to a very long string, it works correctly. The other strings are passed correctly too. Is that some struct alignment issue?
As #MartinR suggested, when I pass the string to the struct's constructor, Swift creates a temporary C char array on the stack, copies the string's data into it and passes its pointer to the constructor. Immediately after that, the char array is no longer valid. Here's an example code demonstrating this:
let s = Struct(string: "string")
print(s.string) // Prints "string"
print("lol") // Overwrite the stack
print(s.string) // Prints "lol"
See https://stackoverflow.com/a/40121697/243225 for possible solutions.

Pointers in Swift

I'm trying to understand the use of pointers in Swift, in particular: Unsafe[Mutable]Pointer and UnsafeRaw[Mutable]Pointer. I have several questions on the subject.
Is UnsafePointer <T> equal to const T * Pointer in ? and UnsafeMutablePointer <T> is equal to T * Pointer in C?
What is the difference between Unsafe[Mutable]Pointer and UnsafeRaw[Mutable]Pointer?
Why does this compile
func receive(pointer: UnsafePointer<Int> ) {
print("param value is: \(pointer.pointee)")
}
var a: Int = 1
receive(pointer: &a) // prints 1
but this gives me an error?
var a: Int = 1
var pointer: UnsafePointer<Int> = &a // error : Cannot pass immutable value of type 'Int' as inout argument
Is UnsafePointer <T> equal to const T * Pointer in ? and UnsafeMutablePointer <T> is equal to T * Pointer in C?
Well, use a bridging header in a Swift app to see how the C pointers are bridged:
const int *myInt;
int *myOtherInt;
bridges to
var myInt: UnsafePointer<Int32>!
var myOtherInt: UnsafeMutablePointer<Int32>!
What is the difference between Unsafe[Mutable]Pointer and UnsafeRaw[Mutable]Pointer?
Swift 3 added a UnsafeRawPointer API to replace the Unsafe[Mutable]Pointer<Void> type. Conversion between pointers of a different type is no longer allowed in Swift. Instead, the API provides interfaces (.assumingMemoryBound(to:) or .bindMemory(to:capacity:)) to bind memory to a type.
With regard to question 3, the ampersand means that the variable is inout. I don't believe you can declare a variable as inout unless it is being used by a function that directly modifies the underlying memory, but I'll let the experts correct me. Instead, use withUnsafePointer.
Thanks to Martin's helpful comment, this syntax was never valid in Swift, and there is no safe way to create "free pointers" to Swift variables.

Printing &self in swift, cannot assign to immutable value of type

This is just an exercise in pointers in swift, but I was trying to write a function that would print the pointer to self, but I kept getting an error "cannot assign to immutable value of type C". Is this something that is even possible in Swift?
class C {
static var c = C()
var a = 1
func printMyPointer() {
printPointer(&self) //cannot assign to immutable value of type C
}
func printPointer(ptr:UnsafePointer<C>) {
print(ptr)
}
}
C.c.printMyPointer()
As already explained in the other answer, you cannot pass a constant
as the argument for an in-out parameter. As a workaround, you can
pass an array, as this will actually pass the address of the first
element:
func printMyPointer() {
printPointer([self])
}
But even simpler, use unsafeAddressOf():
func printMyPointer() {
print(unsafeAddressOf(self))
}
Update for Swift 3: As of Xcode 8 beta 6, unsafeAddressOf
does not exist anymore. You can convert self to a pointer:
print(Unmanaged.passUnretained(self).toOpaque())
or
print(unsafeBitCast(self, to: UnsafeRawPointer.self))
From the Swift Docs:
You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an inout parameter, to indicate that it can be modified by the function.
Since self is immutable, you can't pass it as an inout parameter. Even though the method signature dosen't use inout, Swift treats pointer parameters like inout, according to the Swift blog:
Swift allows pointer parameters to be treated like inout parameters, so you can pass a reference to a var as a pointer argument by using the same & syntax.