Swift define double pointer for struct defined in c - swift

I have a library which contains this function:
void create_pointer(Pointer **pointer);
It takes a pointer's pointer and allocates memory for it. in c, I can do it like this
Pointer *pointer;
create_pointer(&pointer);
then I have a pointer's instance.
But now I want to use this function in Swift. How?
I have no details about Pointer, I only know it's a struct, defined like this
typedef struct Pointer Pointer;

Let's start with a C example
typedef struct {
NSUInteger someNumber;
} SomeStruct;
void create_some_struct(SomeStruct **someStruct) {
*someStruct = malloc(sizeof(SomeStruct));
(*someStruct)->someNumber = 20;
}
In C, you would use it like this:
//pointer to our struct, initially empty
SomeStruct *s = NULL;
//calling the function
create_some_struct(&s);
In Swift:
//declaring a pointer is simple
var s: UnsafePointer<SomeStruct> = UnsafePointer<SomeStruct>.null()
//well, this seems to be almost the same thing :)
create_some_struct(&s)
println("Number: \(s.memory.someNumber)"); //prints 20
Edit:
If your pointer is an opaque type (e.g. void *), you have to use
var pointer: COpaquePointer = COpaquePointer.null()
Note that Swift is not designed to interact with C code easily. C code is mostly unsafe and Swift is designed for safety, that's why the Swift code is a bit complicated to write. Obj-C wrappers for C libraries make the task much easier.

Related

How to reinterpret_cast in Swift?

Our project depends on a C library that declares a general struct
typedef struct
{
SomeType a_field;
char payload[248];
} GeneralStruct
and a more specific one:
typedef struct
{
SomeType a_field;
OtherType other_field;
AnotherType another_file;
YetAnotherType yet_another_field;
} SpecificStruct
We have some examples of its usage in C++ and in some cases it's needed to cast the general one to the specific one like:
GeneralStruct generalStruct = // ...
SpecificStruct specificStruct = reinterpret_cast<SpecificStruct&>(generalStruct)
Is it something like reinterpret_cast available in Swift? I guess I could read the bytes from payload manually, but I'm looking for an idiomatic way
withMemoryRebound(to:capacity:_:) can be used
... when you have a pointer to memory bound to one type and you need to access that memory as instances of another type.
Example: Take the address of the general struct, then rebind and dereference the pointer:
let general = GeneralStruct()
let specific = withUnsafePointer(to: general) {
$0.withMemoryRebound(to: SpecificStruct.self, capacity: 1) {
$0.pointee
}
}
If both types have the same size and a compatible memory layout then you can also use unsafeBitCast(_:to:):
Use this function only to convert the instance passed as x to a layout-compatible type when conversion through other means is not possible.
Warning: Calling this function breaks the guarantees of the Swift type system; use with extreme care.
Example:
let specific = unsafeBitCast(general, to: SpecificStruct.self)

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.

Simple Pointer Operations in Swift?

Let's say I do the following in C++:
int i = 1;
int* ptr = &i;
*ptr = 2;
cout << i << '\n';
And I want to do something similar in swift. Could I do the following?
var i : Int = 1
var iptr : UnsafeMutablePointer<Int> = &i
iptr.memory = 2
print(i)
And achieve the same result?
Yes-ish.
You can't do it exactly as you've attempted in the question. It won't compile. Swift won't let you directly access the address of a value like this. At the end of the day, the reason is mostly because there's simply no good reason to do so.
We do see the & operator in Swift however.
First of all, there is the inout keyword when declaring function parameters:
func doubleIfPositive(inout value: Float) -> Bool {
if value > 0 {
value *= 2
return true
}
return false
}
And to call this method, we'd need the & operator:
let weMadeARadian = doubleIfPositive(&pi)
We can see it similarly used when we have a function which takes an argument of type UnsafeMutablePointer (and other variants of these pointer structs). In this specific case, it's primarily for interoperability with C & Objective-C, where we could declare a method as such:
bool doubleIfPositive(float * value) -> bool {
if (value > 0) {
value *= 2;
return true;
}
return false;
}
The Swift interface for that method ends up looking somethin like this:
func doubleIfPositive(value: UnsafeMutablePointer<Float>) -> Bool
And calling this method from Swift actually looks just like it did before when using the inout approach:
let weMadeARadian = doubleIfPositive(&pi)
But these are the only two uses of this & operator I can find in Swift.
With that said, we can write a function that makes use of the second form of passing an argument into a method with the & operator and returns that variable wrapped in an unsafe mutable pointer. It looks like this:
func addressOf<T>(value: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T> {
return value
}
And it behaves about as you'd expect from your original code snippet:
var i: Int = 1
var iPtr = addressOf(&i)
iPtr.memory = 2
print(i) // prints 2
As noted by Kevin in the comments, we can also directly allocate memory if we want.
var iPtr = UnsafeMutablePointer<Int>.alloc(1)
The argument 1 here is effectively the mount of space to allocate. This says we want to allocate enough memory for a single Int.
This is roughly equivalent to the following C code:
int * iPtr = malloc(1 * sizeof(int));
BUT...
If you're doing any of this for anything other than interoperability with C or Objective-C, you're most likely not Swifting correctly. So before you start running around town with pointers to value types in Swift, please, make sure it's what you absolutely need to be doing. I've been writing Swift since release, and I've never found the need for any of these shenanigans.
Like this (not the only way, but it's clear):
var i : Int = 1
withUnsafeMutablePointer(&i) {
iptr -> () in
iptr.memory = 2
}
print(i)
Not a very interesting example, but it is completely parallel to your pseudo-code, and we really did reach right into the already allocated memory and alter it, which is what you wanted to do.
This sort of thing gets a lot more interesting when what you want to do is something like cycle thru memory just as fast as doing pointer arithmetic in C.

Single-value-tuple as last member of struct in swift

MusicPlayer's API relies on variable length arrays as the last member of a struct to handle passing around data of unknown size. Looking at the generated interface for MusicPlayer, the structs used in this method present their last element in a single value tuple.
example:
struct MusicEventUserData {
var length: UInt32
var data: (UInt8)
}
I doubt that any of this has been officially exposed but has anyone figured out whether this syntax is a red herring or actually significant? I don't think that there is a means to hand arbitrarily sized things via swift but does this help when calling from C?
after test on a playground I can see there is no difference between (Int) and Int type.
Here is my tests :
func testMethod(param1: Int, param2: (Int)) -> Int{
return param1 + param2
}
testMethod(2, 3) // return 5
testMethod(3, (6)) // return 9
About the calling in C, I just think it is a little bug on the bridging from ObjC to swift
MusicPlayer is no longer exported as above. As of Xcode 6.3b1
typedef struct MusicEventUserData
{
UInt32 length;
UInt8 data[1];
} MusicEventUserData;
This is much closer to the C declaration. It still does not completely explain how to deal with the API in swift but that is another question.