본문 바로가기

IOS

Swift Objective C 네임 맹글링(Name Mangling) 문제

 

Swift로 작성된 함수를 기본적으로 C 인터페이스에서 동작하는 Unity 나 Unreal 등의 게임엔진 또는 직접 C 코드에서 호출하게 되는 상황에서 네임 멩글링(Name Mangling)으로 인한 경고 또는 에러를 경험할 수 있다.


C 인터페이스에서 동작하는 이유는 다양한 언어 간 상호 운용이 가능하기 때문.

 

C++ 및 Swift는 함수 오버로딩네임스페이스를 지원하기 위해 함수 이름을 내부적으로 변경하는 "네임 맹글링"을 사용한다.

Swift에서는 특히 Objective-C에서 사용할 수 있도록 @objc, @objcMember 와 같은 애트리뷰트(attribute)를 사용하는 것과 관련이 있다. 

 

좀 더 자세히 설명한다면

 

네임 맹글링(Name Mangling)은 컴파일러가 함수와 변수의 이름을 고유하게 식별하기 위해 내부적으로 이름을 변경하는 과정이다.

 

C++의 경우, 컴파일러는 내부적으로 함수의 고유 식별을 위해 이름을 변경한다

// 선언한 함수
void func(int);
void func(double);

// 컴파일러 식별 함수 이름
_Z4funci  // func(int)
_Z4funcd  // func(double)

 

위처럼 네임 맹글링은 함수의 서명(매개 변수 유형, 반환 유형 등)을 포함하여 고유한 식별자를 생성하게 된다. 

 

반면, C 언어는 네임 맹글링을 사용하지 않기 때문에 함수 이름이 단순하게 유지된다.
C언어는 함수 오버로딩을 지원하지 않는다. 

void func(int);

컴파일러에 의해 다른 고유한 식별자로 인식되지 않는다.

 

C 기반의 라이브러리, 프레임워크들은 C 인터페이스를 기대하고 있기 때문에, Cpp, Swift 코드가 C 인터페이스를 통해 사용될 경우에는 네임 멩글링이 없는 호출자를 사용해야 한다.

 

 

예시

@objc public class KinClass: NSObject {
    @objc public func calculateTotal(person: Int) -> Int {
        return persen * 10
    }
}

상단의 예시 코드는 Swift 코드를 Objective-C 및 C에서 사용하기 위해 @objc 애트리뷰트를 사용한 예시이다.

위처럼 @objc 애트리뷰트를 붙일 경우, Objective-C 런타임에서 함수 사용이 가능해진다.

 

Swift -> C 인터페이스 노출

// KinBridge.h

extern "C" {
    int calculateTotal(int person);
}

여기서 extern "C" 를 사용하는 이유는 네임 맹글링(Name Mangling)을 피하기 위함이다.

extern "C" -> C++와 Objective-C++에서 함수의 이름 맹글링을 방지하고, C 스타일의 함수 이름과 링크 관리를 유지하도록 컴파일러에 지시하는 키워드

 

 

위에서 언급한대로 
C++ 및 Swift는 함수 오버로딩 네임스페이스를 지원하기 위해 함수 이름을 내부적으로 변경하는 "네임 맹글링"을 사용한다.

 

반면, 

extern "C" 내부에 작성할 경우, calculateTotal을 C 스타일의 인터페이스로 노출한다. 

 

// KinBridge.mm

#import "MyProject-Swift.h" // Swift 코드를 가져옴
#import "KinBridge.h"

int calculateTotal(int person) {
    KinClass *swiftClass = [[KinClass alloc] init];
    return [swiftClass calculateTotalWithPerson:person];
}

 

이제 C 인터페이스로 노출된다 하더라도 C 컴파일러와 동일한 방식으로 함수 이름이 유지되기 때문에 C 인터페이스에서도 호출이 가능해진다.