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 で変更します
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 がないというのです, コンパイルできてるのに, みつからないだと…
実際 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; } [/cpp] <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