13

Sorry for the title, I can't find words to describe my question in few words.

I already know that swift can use struct written in c. For example

In Bridging-Header.h

typedef struct {
    int x;
    int y;
} Pointer;

then I can use Pointer directly.

But in my case, I have a library written in C. There are many structs with hidden implement. For example:
In Briding-Header.h

typedef struct Pointer Pointer;

I can't use Pointer any more, got unknown type. In my library Pointer is used as

create_pointer(Pointer **pointer);

Any help is appreciated!

P.S I have no .h file which define struct Pointer. All details about Pointer is hide, access them by function, for example

int getx(Pointer *pointer);

Here is my full test code:
user_input.c

#include <stdio.h>

#include "user_input.h"

struct Pointer {
    int x;
    int y;
};

void get_user_input(int *user_input) {
    scanf("%i", user_input);
}

void init_pointer(Pointer *point) {
    point->x = 20;
    point->y = 20;
}

user_input.h

#ifndef __user_input_h__
#define __user_input_h__

typedef struct Pointer Pointer;

void init_pointer(Pointer *p);

#endif

Bridging-Header.h

#include "user_input.h"

main.swift

import Foundation
var pointer:Pointer = Pointer(x:10, y:20)

Xcode give me this error: Pointer undefined

Werner Henze
  • 16,404
  • 12
  • 44
  • 69
galilio
  • 307
  • 1
  • 3
  • 13
  • 1
    As an addendum to my updated answer, it appears that structs may be problematic. I've been looking through the Swift docs in the Xcode seed and I can't find anything that talks explicitly about initializing typedef-ed structs and using them. I'm leaving my answer in the hopes that it will help someone trying to call C functions, but structs are still a grey area, it seems. – alesplin Jun 06 '14 at 05:16

3 Answers3

12

Bridging-Header.h

#include "user_input.h"

user_input.c

#include <stdlib.h>

struct Pointer {
    int x;
    int y;
};

Pointer *create_pointer() {
    Pointer *p = malloc(sizeof(struct Pointer));
    if (p) {
        p->x = 20;
        p->y = 20;
    }
    return p;
}

void delete_pointer(Pointer *p) {
    free(p);
}

int pointer_x(Pointer *p) {
    return p->x;
}

int pointer_y(Pointer *p) {
    return p->y;
}

user_input.h

#ifndef __user_input_h__
#define __user_input_h__

typedef struct Pointer Pointer;
Pointer *create_pointer();
void delete_pointer(Pointer *p);
int pointer_x(Pointer *p);
int pointer_y(Pointer *p);

#endif

main.swift

import Foundation

var pointer: COpaquePointer = create_pointer()
println("\(pointer_x(pointer)), \(pointer_y(pointer))")
delete_pointer(pointer)

// Writing the wrapper class could be helpful.

class CPointer {
    var _ptr: COpaquePointer

    init() {
        _ptr = create_pointer()
        assert(_ptr, "Failed on create_pointer()")
    }

    deinit {
        delete_pointer(_ptr)
    }

    var x: Int {
        get { return Int(pointer_x(_ptr)) }
    }

    var y: Int {
        get { return Int(pointer_y(_ptr)) }
    }
}

var p = CPointer()
println("\(p.x), \(p.y)")
kroisse
  • 515
  • 1
  • 4
  • 9
1

You should be OK if you include the original header where Pointer is typedef-ed in ___Bridging-Header.h

So for example if you have foo.h where you declare your struct and your functions, then instead of doing any additional typdef calls in your bridging header just #import foo.h

Then your Swift code should be able to see the symbols declared in foo.h

Update:

What you need:

  1. Say "foo.h" is the header file where Pointer is typedef-ed. Also say that "foo.c" is the file where createPointer() is implemented.
  2. You'll need to create a Swift project in Xcode. Add "foo.h" and "foo.c" to the project.
  3. Add a header file to the project called "foo-Bridging-Header.h" (Sometimes Xcode asks if you want to create a Bridging Header when you add a .c or .m file to the project, but with the Developer Seed I haven't observed this to be consistent yet).
  4. In "foo-Bridging-Header.h", you'll need to #include foo.h
  5. Once you have done this, you should be able to call any of the symbols from "foo.h" from the "main.swift" file in your project.

For example, I have a Swift project. In this project I have a Swift file (main.swift), a C header (test.h), a C source file (test.c), and a Bridging Header (test-Bridging-Header.h).

Their contents are as follows:

  1. test.h:
void
printFoo();
  1. test.c:
#include <stdio.h>
#include "test.h"

void
printFoo() {
    printf("foo\n");
}
  1. test-Bridging-Header.h:
#import "test.h"
  1. main.swift:
import Foundation

println("Hello, World!")

printFoo()

When run, this outputs:

Hello, World!
foo
alesplin
  • 1,332
  • 14
  • 23
0

After change my question, I got an answer.

When the struct implements in hidden, this is called "opaque"

so I can use COpaquePointer.

var pointer: COpaquePointer = COpaquePointer.null()
// some init code.
init_pointer(pointer);
galilio
  • 307
  • 1
  • 3
  • 13
  • Your code will work like this C code: `Pointer *pointer = NULL; init_pointer(pointer);` This makes `pointer` point nowhere on the memory, and leads `init_pointer()` to the memory error. – kroisse Jun 13 '14 at 14:18
  • If Swift doesn't know the shape of the C structure, There should be several functions in C who know how allocate, initialize, and destroy it. – kroisse Jun 13 '14 at 14:20