Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
478 views
in Technique[技术] by (71.8m points)

macos - Swift: Pass Uninitialized C Structure to Imported C function

I'm aware of this answer, but this is not the same thing - thats passing a pointer to be initialised with an allocation.

I'm interfacing with a C library that has the following structure definition:

typedef struct myStruct { unsigned char var [50]; } myStruct;

There is a function to which you pass the address of the structure - normally stack based not heap, thus:

myStruct mine;
initMyStruct(&mine);

This initialises the content of the struct - the caller does not know the internal format of the memory, hence the obfuscation.

In Swift, I'm creating a class which will encapsulate the structure and interface with other C functions which operates on it.

class MyClass {

    var mine : myStruct

    init() {

        initMyStruct(&mine)
        // Error: Variable 'self.msg' passed by reference before being initialized

    }

}

I can't for the life of me work out how to initialise the structure, or use a point instead if that is an alternative.

mine = myStruct()
// Fails because you aren't providing the value of the member 'var'

mine = myStruct((CUnsignedChar(), CUnsignedChar(), /*... repeat to 50 */))
// Cannot find an overload for 'init' that accepts the arguments

Please note, this is passing the address of an already allocated (stack based) structure to a function that has been imported as

CInt initMyStruct(str: CMutablePointer<myStruct>)

It is NOT passing a pointer to be allocated by the C library in question which seems to be a more common requirement and is answered elsewhere.

Swift currently doesn't support fixed size arrays either.

I can't see how to satisfy the initialisation of the structure or make Swift think that it is going to be done so by the call.

Any help greatly appreciated!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

First, let's define our C code for testing:

typedef struct my_struct {
    unsigned char buffer[10];
} my_struct;

void my_struct_init(my_struct *my_s) {
    for (int i = 0; i < 10; i++) {
        my_s->buffer[i] = (char) i;
    }
}

In Swift, we have two options:

1. Struct on the stack

var my_s: my_struct = ...

However, we have to initialize it somehow. Every struct has a default initializer

var my_s: my_struct = my_struct(buffer: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0))

Note that in this case the buffer[10] has been translated to Swift as a 10-tuple.

Now we can call:

my_struct_init(&my_s)
print("Buffer: (my_s.buffer)") // Buffer: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

However, the more complex is the struct, the more difficult is to use the default initializer.

2. Struct on the heap

This is similar to using malloc and free in C:

var my_s_pointer = UnsafeMutablePointer<my_struct>.allocate(capacity: 1)
print("Buffer: (my_s.buffer)") // Buffer: (some random values)

my_struct_init(my_s_pointer)
print("Buffer: (my_s_pointer.memory.buffer)") // Buffer: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

my_s_pointer.deallocate()

Combine both approaches

The following function will initialize any struct:

func initStruct<S>() -> S {
    let struct_pointer = UnsafeMutablePointer<S>.allocate(capacity: 1)

    let struct_memory = struct_pointer.pointee
    struct_pointer.dealloate()

    return struct_memory
}

var my_s: my_struct = initStruct()
my_struct_init(&my_s)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...