ObjectiveCからC++

もうひとつのプロフェッショナルプログラマーからの転送です。

iOSやMac OS アプリケーションを作っている時, 主要な部分をObjective-C で書き, C, C++ ライブラリや, 過去の資産のコードを使いたいというケースがあるはずです。
XCodeは, C, C++のふつうのプログラムなんかでもデバッグの威力を発揮してくれるのでは, と思っています(Eclipse CDTよりもいいんじゃないのかな)。

こういったケースでは, Objective-C のコードから, C, C++ を呼び出すわけです。Cは特に問題ありませんがC++ にはちょっとした工夫が必要です。

Objective-C は C です
これさえわかっていれば, 実はどうってことないわけですが…

解決策

  • extern C を使って, C 関数として呼び出す
  • Objective-C++ (.mm) を使って, C++ のコードとしてObjective-Cを扱う

ちょっとした例をあげながら確認していきましょう

Objective-C から C を呼び出す

test.c(C source), test.h(C header), CWrapper.h(C header), CWrapper.m(Objective-C source)

というソースを用意しました

test.c

#include "test.h"
#include
void testFunc()
{
printf("Hello C\n");
}

test.h

#ifndef AudoSamples_testc_h
#define AudoSamples_testc_h
void testFunc();
#endif

CWrapper.h

#include "test.h"
@interface CWrapper : NSObject
+(void)callC;
@end

CWrapper.m

#import "CWrapper.h"
@implementation CWrapper
+(void)callC
{
testFunc();
}
@end

Use

[CWrapper callC];

このコードは問題なく動作します

Objective-CからC++を呼び出す

ex) testcp.cpp(C++ source), testcp.h(C++ header)をさらに追加しました

testcp.h

#ifdef __AudioSamples__File__
#define __AudioSamples__File__
void testCpp();
#endif

これを, C++ のヘッダーに変えましょう。XCode の、Inspector で変更します
headerpro

testcp.cpp

#include "testcp.h"
void testCpp()
{
std::cout << "Hello cpp" << std::endl;
}

先ほどの, CWapper.h を変更します

CWapper.h

#include "test.h"
#include "testcp.h"
@interface CWrapper : NSObject
+(void)callC;
+(void)callCpp;
@end

先ほどの, CWrapper.mを変更します

CWrapper.m

@implementation CWrapper
+(void)callC
{
testFunc();
}
+(void)callCpp
{
testCpp();
}
@end

このソースはコンパイルはできますが, リンクができません。

Apple Match-O Linker Error Undefined symbols for architecture i386:

といったように, C++ で作った関数 testCpp がないというのです, コンパイルできてるのに, みつからないだと…
linkerror

実際 testcp.o というObject ファイルは生成されているようです。ですが中身が, C++ の関数になっているので うまくリンクできません。
UNIX コマンド nm で確認してみるとよくわかります

nm testcp.o 

これはおいておいて, 解決策にまいりましょう

extern C を使って, C 関数として呼び出す

定義部分のところで, Cの関数として呼び出すように変更します
testcp.h を変更します

#ifdef __C__File__
#define __C__File__

#ifdef __cplusplus
extern "C" {
#endif
void testCpp();
#ifdef __cplusplus
}
#endif
#endif

これで, Objective-C から, C++ を呼び出せるようになりました

Objective-C++ (.mm) を使って, C++ のコードとしてObjective-Cを扱う

こちらは, Objective-C++ というのを使って, Objective-CをC++ としてしまいます
例を変えて説明しましょう
ex) pure.cpp(C++), pure.h(C++), CpWrapper.h(C++), CpWrapper.mm(Objective-C++)

pure.h

#ifndef __CP__pure__
#define __CP__pure__
void pureCpp();
#endif

pure.cpp

#include "pure.h"
#include <iostream>

void pureCpp()
{
   std::cout << "I am CP9" << std::endl;
}
&#91;/cpp&#93;

<h4>CpWrapper.h</h4>
[cpp]
#import <Foundation/Foundation.h>
#include "pure.h"
@interface CpWrapper : NSObject
@end

CpWrapper.mm

#import "CpWrapper.h"
@implementation CpWrapper
void pureCppCall()
{
   pureCpp();
}
@end