mike-neckのブログ

Java or Groovy or Swift or Golang

CPP(C++) の関数を C 言語から呼び出す方法

C 言語を業務でやったことがほとんどない + CPP は完全に触ったことがないので、いろいろググりつつやってみた。

f:id:mike_neck:20180609045321p:plain

最終的に Swift から C++ で定義されているオブジェクトの関数を呼び出すところまでが目標。


まず、次のような C++ の関数が定義されているものとする。

cpp_lib.h

#ifndef CPP_LIB_H
#define CPP_LIB_H

#include <string>

void show(std::string const& message);

#endif //CPP_LIB_H

cpp_lib.cpp

#include "cpp_lib.h"
#include <string>
#include <iostream>

void show(std::string const& message)
{
  std::cout << message << std::endl;
}

これは単純に std::string を受け取って、 標準出力に出力する C++ の関数。


あってるかどうかわからないが、 C の文字列をこの関数に渡すには 一度 char の配列を std::string に変換する層が必要になる。

cpp_bridge.h

#ifndef CPP_BRIDGE_H
#define CPP_BRIDGE_H

#ifdef __cplusplus
extern "C"
#endif
void show_bridge(char const* message);

#endif // CPP_BRIDGE_H

cpp_bridge.cpp

#include "cpp_bridge.h"
#include "cpp_lib.h"

#include <string>

#ifdef __cplusplus
extern "C"
#endif
void show_bridge(char const* message)
{
  std::string msg(message);
  show(msg);
}

C++コンパイルした関数は次の記事によるとシグネチャーが異なるらしいので、 extern "C" を付ける必要がある。

d.hatena.ne.jp


最後に これを C のアプリケーションを書く。

#include "cpp_bridge.h"

int main(int argc, char *argv[])
{
  char* message = "hello";
  show_bridge(message);
}

次にコンパイルする。コンパイラーは clang-3.8 を使う。

clang++-3.8 -c -Wall -o .build/cpp_lib.o cpp_lib.cpp
clang++-3.8 -c -Wall -o .build/cpp_bridge.o cpp_bridge.cpp
clang-3.8 -c -Wall -o .build/main.o main.c
clang++-3.8 -Wall -o .build/main .build/main.o .build/cpp_bridge.o .build/cpp_lib.o