使用Objective-C++与Objective-C的链接器问题



目前我有一个使用Objective-C的iOS项目。出于性能原因,我实现了Objective-C++代码,如下所示:

基线11.mm

#include <string>
#include "base11.h"
static const std::string characters = "0123456789_";
const char* to_base11(long n) {
// some c++ code here
}
long from_base11(const char* input) {
// some c++ code here
}

base11.h

#ifndef base11_h
#define base11_h
#include <stdio.h>
const char* to_base11(long n);
long from_base11(const char* input);
#endif /* base11_h */

当然,我为类使用了.mm扩展,并且我只使用普通的C函数参数和返回类型。

然后我有一个Objective-C类,它将这些C++函数封装在以下方法中:

Util.m

#include "base11.h"
+(NSString*) convertBase10ToBase11:(long) base10 {
const char* base11 = to_base11(base10);
return [NSString stringWithUTF8String:base11];
}
+(NSNumber*) convertBase11ToBase10:(NSString*) base11 {
const char* input = [base11 UTF8String];
return @(from_base11(input));
}

以及Util.h:

@interface Util : NSObject
+(NSString*) convertBase10ToBase11:(long) base10;
+(NSNumber*) convertBase11ToBase10:(NSString*) base11;
@end

然而,这会产生以下编译错误:

Undefined symbols for architecture x86_64:
"_from_base11", referenced from:
+[Util convertBase11ToBase10:] in Util.o
"_to_base11", referenced from:
+[Util convertBase10ToBase11:] in Util.o
ld: symbol(s) not found for architecture x86_64

然而,这很奇怪。我选择不对Util.m类使用.mm扩展,因为我在那里不使用任何C++代码。还要注意,base11.h头文件也没有使用任何C++代码。那么,为什么我会出现这个错误呢?根据这篇文章,我的方法应该是正确的:

如何从目标c类调用.mm文件上的方法

这是函数符号名称中的问题。C++允许使用相同名称和不同原型的函数。因此,当使用C++/Objective-C++编译函数时,它得到了描述其原型的符号名称,并使其具有唯一性。

所以您需要强制编译器使用C的符号名称。您可以通过在函数原型之前添加extern "C"来实现这一点。但是,如果在C和C++源文件中都使用这个头,那就不太方便了,因为C不知道它是extern "C"

幸运的是CoreFoundation已经解决了这个问题。您可以查看他们是如何声明CFString.hCFArray.h的。

所以您只需要使用CoreFoundation的宏:CF_EXTERN_C_BEGINCF_EXTERN_C_END

#ifndef base11_h
#define base11_h
#include <stdio.h>
#include <CoreFoundation/CFBase.h>
CF_IMPLICIT_BRIDGING_ENABLED
CF_EXTERN_C_BEGIN
const char* to_base11(long n);
long from_base11(const char* input);
CF_EXTERN_C_END
CF_IMPLICIT_BRIDGING_DISABLED
#endif /* base11_h */

最新更新