【问题标题】:Swift use c structSwift 使用 c 结构
【发布时间】:2014-07-25 21:36:52
【问题描述】:

抱歉标题,我无法用几句话来描述我的问题。

我已经知道 swift 可以使用用 c 编写的 struct。例如

在 Bridging-Header.h 中

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

那我就可以直接使用Pointer了。

但在我的例子中,我有一个用 C 编写的库。有许多带有隐藏实现的结构。例如:
在 Briding-Header.h

typedef struct Pointer Pointer;

我不能再使用指针了,类型未知。在我的库中,指针用作

create_pointer(Pointer **pointer);

感谢任何帮助!

P.S 我没有定义结构指针的 .h 文件。关于指针的所有细节都是隐藏的,通过函数访问它们,例如

int getx(Pointer *pointer);

这是我的完整测试代码:
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 给我这个错误:指针未定义

【问题讨论】:

  • 作为我更新答案的附录,似乎结构可能有问题。我一直在查看 Xcode 种子中的 Swift 文档,但我找不到任何明确谈论初始化 typedef 结构和使用它们的内容。我留下我的答案,希望它能帮助尝试调用 C 函数的人,但结构似乎仍然是一个灰色区域。

标签: c pointers struct swift


【解决方案1】:

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

ma​​in.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)")

【讨论】:

  • 正是我想要的!包装可能是最安全的方式,虽然有点烦人。
【解决方案2】:

如果在 ___Bridging-Header.h 中包含 Pointer 类型定义的原始标头,则应该没问题

因此,例如,如果您在 foo.h 中声明了您的结构和函数,则无需在桥接头中执行任何额外的 typdef 调用,只需 #import foo.h

那么你的 Swift 代码应该能够看到 foo.h 中声明的符号

更新:

你需要什么:

  1. 说“foo.h”是指针被 typedef-ed 的头文件。还要说“foo.c”是实现 createPointer() 的文件。
  2. 您需要在 Xcode 中创建一个 Swift 项目。将“foo.h”和“foo.c”添加到项目中。
  3. 在项目中添加一个名为“foo-Bridging-Header.h”的头文件(有时 Xcode 会在您向项目中添加 .c 或 .m 文件时询问您是否要创建桥接头,但使用开发人员种子我还没有观察到这是一致的)。
  4. 在“foo-Bridging-Header.h”中,您需要#include foo.h
  5. 完成此操作后,您应该可以从项目的“main.swift”文件中调用“foo.h”中的任何符号。

例如,我有一个 Swift 项目。在这个项目中,我有一个 Swift 文件 (main.swift)、一个 C 头文件 (test.h)、一个 C 源文件 (test.c) 和一个桥接头 (test-Bridging-Header.h)。

它们的内容如下:

  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()

运行时,输出:

Hello, World!
foo

【讨论】:

  • 最重要的是我没有定义结构的.h,只有带有typedef的.h。
  • 对。这就是您要包含在桥接头中的那个。
  • 我测试过但失败了。你能逐步给出类似的东西吗?
  • 我更新了我的答案。我不确定双指针等规则是什么。但这应该允许您从 Swift 项目中调用 C 代码。
  • 谢谢,你提到的方法我已经测试过了。有用。但是双指针还是不行
【解决方案3】:

更改我的问题后,我得到了答案。

当结构在隐藏中实现时,这称为“不透明”

所以我可以使用 COpaquePointer。

var pointer: COpaquePointer = COpaquePointer.null()
// some init code.
init_pointer(pointer);

【讨论】:

  • 你的代码会像下面这样运行 C 代码:Pointer *pointer = NULL; init_pointer(pointer); 这使得pointer 在内存中无处指向,并导致init_pointer() 出现内存错误。
  • 如果 Swift 不知道 C 结构的形状,那么 C 中应该有几个函数知道如何分配、初始化和销毁​​它。
猜你喜欢
  • 2014-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多