Swift에서 C를 호출하는 방법?


136

Swift에서 C 루틴을 호출하는 방법이 있습니까?

많은 iOS / Apple 라이브러리는 C 전용이며 여전히 전화 할 수 있기를 바랍니다.

예를 들어, 신속하게 objc 런타임 라이브러리를 호출 할 수 있기를 원합니다.

특히 iOS C 헤더를 어떻게 연결합니까?

답변:


106

예, 물론 Apples C 라이브러리와 상호 작용할 수 있습니다. 방법은 다음과 같습니다 .
기본적으로 C 유형, C 포인터 등은 Swift 객체로 변환됩니다. 예를 들어 intSwift 의 C 는 a CInt입니다.

C와 Swift를 연결하는 방법에 대한 간단한 설명으로 사용할 수있는 또 다른 질문에 대한 작은 예를 작성했습니다.

main.swift

import Foundation

var output: CInt = 0
getInput(&output)

println(output)

UserInput.c

#include <stdio.h>

void getInput(int *output) {
    scanf("%i", output);
}

cliinput-Bridging-Header.h

void getInput(int *output);

여기 에 원래 답변이 있습니다.


1
나는 ios / swift를 처음 사용합니다. 빠른 파일에서 #include <asl.h>의 로깅 c-function을 사용하고 싶습니다. 누군가?
Dmitry Konovalov

C ++, .cpp 파일과 호환됩니까?
Carlos.V

C ++ 파일을 직접 사용하려면 objective-C 래퍼를 만들어야합니다. 구현 (.mm 파일에 자체적으로 있어야 함)에 Objective-C ++ 코드 (하나의 파일에 Objective-C 및 C ++)와 인터페이스 (자체 .h에 있어야 함)가 포함되기를 원할 것입니다 헤더 파일)에는 순수한 Objective-C 코드가 포함되어야하므로 구현에서 C ++ 유형을 Objective-C 유형으로 변환하여 Swift에 노출시켜야합니다. 그런 다음 objective-c 브리징 헤더를 사용하여 해당 헤더를 가져올 수 있습니다.
William T Froggard

2
“물론 Apples C 라이브러리와 상호 작용할 수 있습니다 . 올바르지 않습니다. 당신은 상호 작용할 수 있는 모든는 애플의 제한 한정되지 않으며에서 C 라이브러리.
Slipp D. Thompson


9

컴파일러는 Objective-C와 마찬가지로 C API를 Swift로 변환합니다.

import Cocoa

let frame = CGRect(x: 10, y: 10, width: 100, height: 100)

import Darwin

for _ in 1..10 {
    println(rand() % 100)
}

문서에서 Objective-C API와 상호 작용을 참조하십시오 .


1
예를 들어 주셔서 감사합니다. 당신 말이 맞습니다. 어떻게 작동하는지 알 수 있습니다. 그러나 실제로 내 질문에 대답하지는 않습니다. 이는 Apple C 라이브러리를 호출하는 방법이었습니다. 그러나 가장 가깝습니다.
Blaze

그 문서의 다른 곳을보십시오. 예를 들어 CoreFoundation 스타일의 "개체"( CFTypeRef)는 Swift 개체로 변환됩니다. 그러나 ObjCRuntime.h 함수의 대부분은 Swift에 의미가 없습니다.
rickster 2016 년

"대부분의 ObjCRuntime.h 함수는 Swift에 의미가 없습니다."왜 그렇게 말합니까? 헤더를 가져 와서 브리지하는 방법을 찾아야한다고 생각합니다. 어색해 보이지만 갈 길이라고 생각합니다.
Blaze

5

XCode를 처음 접하고 Leandro의 답변에 게시 된 스 니펫을 시도하려는 경우를 대비하여 :

  1. 파일-> 신규-> 프로젝트
  2. 프로젝트 사전 설정으로 명령 행 도구를 선택하고 프로젝트 이름을 "cliinput"
  3. 프로젝트 탐색기 (왼쪽의 파란색 패널)를 마우스 오른쪽 단추로 클릭하고 "새 파일 ..."을 선택하십시오.
  4. 드롭 다운 대화 상자에서 파일 이름을 "UserInput"으로 지정하십시오. "또한 헤더 파일 작성"상자를 선택 취소하십시오. "Next"를 클릭하면 XCode가 Bridging-Header.h 파일을 생성해야하는지 묻는 메시지가 나타납니다. "예"를 선택하십시오.
  5. 위의 Leandro 답변에서 코드를 복사하여 붙여 넣습니다. 재생 버튼을 클릭하면 터미널에서 컴파일되고 실행되며 xcode의 하단 패널에 내장되어 있습니다. 터미널에 숫자를 입력하면 숫자가 반환됩니다.

4

이 게시물 에는 clang의 모듈 지원을 사용하여이를 수행하는 방법에 대한 좋은 설명도 있습니다. .

CommonCrypto 프로젝트 에서이 작업을 수행하는 방법에 따라 구성되어 있지만 일반적으로 Swift 내에서 사용하려는 다른 C 라이브러리에서 작동해야합니다.

zlib에 대해 이것을 간단하게 실험했습니다. 새로운 iOS 프레임 워크 프로젝트를 만들고 다음과 같은 module.modulemap 파일을 포함하는 zlib 디렉토리를 만들었습니다.

module zlib [system] [extern_c] {
    header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/zlib.h"
    export *
}

그런 다음 대상-> 라이브러리와 바이너리 연결에서 항목 추가를 선택하고 libz.tbd를 추가했습니다.

이 시점에서 빌드 할 수 있습니다.

그런 다음 다음 코드를 작성할 수있었습니다.

import zlib

public class Zlib {
    public class func zlibCompileFlags() -> UInt {
        return zlib.zlibCompileFlags()
    }
}

당신은하지 않습니다 C 함수와 같은 FUNC 스위프트 클래스라는 이름의 위의 경우에 I를 제외하고, 앞에있는 ZLIB 라이브러리 이름을 넣어, 및 자격없이 스위프트의 FUNC의 끝이 응용 프로그램은 정지 할 때까지 반복적으로 호출된다.


3

c ++의 경우 다음과 같은 오류가 발생합니다.

  "_getInput", referenced from: 

C ++ 헤더 파일도 필요합니다. 함수에 c-linkage 를 추가 한 다음 브리지 헤더에 헤더 파일을 포함하십시오.

스위프트 3

UserInput.h

#ifndef USERINPUT_H
#define USERINPUT_H    

#ifdef __cplusplus
extern "C"{
#endif

getInput(int *output);

#ifdef __cplusplus
}
#endif

UserInput.c

#include <stdio.h>

void getInput(int *output) {
    scanf("%i", output);
}    

main.swift

import Foundation
var output: CInt = 0
getInput(&output)
print(output)

cliinput-Bridging-Header.h

#include "UserInput.h"

여기에 이것을 설명 하는 원본 비디오가 있습니다


작동하지 않는 경우 __OBJC브리징 헤더에 체크 표시 를 추가 하십시오.#ifdef __OBJC @import UIKit; #endif
Chris Yim

1

포인터를 다룰 때 약간 다른 볼로 왁스처럼 보입니다. 다음은 C POSIX read시스템 호출을위한 것입니다.

enum FileReadableStreamError : Error {
case failedOnRead
}

// Some help from: http://stackoverflow.com/questions/38983277/how-to-get-bytes-out-of-an-unsafemutablerawpointer
// and https://gist.github.com/kirsteins/6d6e96380db677169831
override func readBytes(size:UInt32) throws -> [UInt8]? {
    guard let unsafeMutableRawPointer = malloc(Int(size)) else {
        return nil
    }

    let numberBytesRead = read(fd, unsafeMutableRawPointer, Int(size))

    if numberBytesRead < 0 {
        free(unsafeMutableRawPointer)
        throw FileReadableStreamError.failedOnRead
    }

    if numberBytesRead == 0 {
        free(unsafeMutableRawPointer)
        return nil
    }

    let unsafeBufferPointer = UnsafeBufferPointer(start: unsafeMutableRawPointer.assumingMemoryBound(to: UInt8.self), count: numberBytesRead)

    let results = Array<UInt8>(unsafeBufferPointer)
    free(unsafeMutableRawPointer)

    return results
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.