文字列受け渡し
class Hello { companion object { init { System.loadLibrary("Hello") } } external fun printHello() external fun printNative(str:String, len:Int); } fun main(args: Array<String>) { Hello().printHello() val str = "hello form kotoln" Hello().printNative(str, str.length) }
でcpp側は
#include "Hello.h" #include <iostream> #include <string> extern "C" { JNIEXPORT void JNICALL Java_Hello_printHello (JNIEnv *env, jclass obj) { std::cout << "hello cpp" << std::endl; } JNIEXPORT void JNICALL Java_Hello_printNative (JNIEnv *env, jclass obj, jstring str, jint len) { /// charに変換 jboolean iscopy; const char* msgStr = env->GetStringUTFChars(str, &iscopy); char* copiedChars = strdup(msgStr); env->ReleaseStringUTFChars(str, msgStr); env->DeleteLocalRef(str); printf("%s\n", copiedChars); } }
でいけた。 が、おそらくこの辺の文字コードの話がいるはず…。
Java とか Android (DEX) の MUTF-8 (Modified UTF-8) って何者よ?っていう話 - bearmini's blog
とか
java, a unicode char will be encoded with 4 bytes (utf16). jstring will container characters utf16 std::string in c++ is essentially a string of bytes, not characters,not characters we have convert utf16 to bytes.
とか
- 返却値
class Hello { companion object { init { System.loadLibrary("Hello") } } external fun printHello() external fun printNative(str:String, len:Int): Boolean; } fun main(args: Array<String>) { Hello().printHello() val str = "hello form kotoln" val ret = Hello().printNative(str, str.length) println("ret = " + ret) }
#include "Hello.h" #include <iostream> #include <string> extern "C" { JNIEXPORT void JNICALL Java_Hello_printHello (JNIEnv *env, jclass obj) { std::cout << "hello cpp" << std::endl; } JNIEXPORT jboolean JNICALL Java_Hello_printNative (JNIEnv *env, jclass obj, jstring str, jint len) { /// charに変換 jboolean iscopy; const char* msgStr = env->GetStringUTFChars(str, &iscopy); char* copiedChars = strdup(msgStr); env->ReleaseStringUTFChars(str, msgStr); env->DeleteLocalRef(str); printf("%s\n", copiedChars); return true; } }
kotlinでhelloworld
class Hello { companion object { init { System.loadLibrary("Hello") } } external fun printHello() } fun main(args: Array<String>) { Hello().printHello() }
kotlinc hello.kt
前回同様ライブラリを用意して実行
kotlin HelloKt
hello world
fun main(args: Array<String>) { println("Hello, World!") } ```` として
kotlinc hello.kt
でコンパイル。できたら実行
kotlin HelloKt
cppでhelloworld
cのときと同様でhello.cppを作る。
#include "Hello.h" #include <iostream> extern "C" { JNIEXPORT void JNICALL Java_Hello_printHello (JNIEnv *env, jclass obj) { std::cout << "hello cpp" << std::endl; } }
あとはコンパイル時に-libc++をつける。
gcc -shared -I/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/include/darwin Hello.cpp -o libHello.dylib -lstdc++
他は同じ
cでhelloworld
java側を用意
public class Hello { static{ System.out.println(java.library.path); System.loadLibrary("Hello"); } static native void printHello(); public static void main(String args[]){ printHello(); } }
javac Hello.java
C側を作成、ヘッダ作成
javah Hello
#include <jni.h> /* Header for class Hello */ #ifndef _Included_Hello #define _Included_Hello #ifdef __cplusplus extern "C" { #endif /* * Class: Hello * Method: printHello * Signature: ()V */ JNIEXPORT void JNICALL Java_Hello_printHello (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
#include "Hello.h" #include <stdio.h> JNIEXPORT void JNICALL Java_Hello_printHello (JNIEnv *env, jclass obj) { printf("hello\n"); }
cをコンパイルするために含めるjniのヘッダーを入れるためjdkの場所を探す。
/usr/libexec/java_home -V
ライブラリ作成
gcc -shared -I/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/include/darwin Hello.c -o libHello.dylib
使うライブラリを実行時に指定して実行
java -Djava.library.path=. Hello
LD_LIBRARY_PATHに設定すると良い?
チュートリアル2
さらに簡単な例
#include <rxcpp/rx.hpp> rxcpp::observable<std::string> twice(std::string word) { return rxcpp::observable<>::just(word + word); } rxcpp::observable<int> length(std::string word) { int l = (int)word.length(); return rxcpp::observable<>::just(l); } rxcpp::observable<std::string> times(std::string word, int times) { auto r = word; for (int i=0;i<times;i++) { r = r + word; } return rxcpp::observable<>::just(r); } void useRxCpp() { auto ob = rxcpp::observable<>::just("poi") .flat_map([=](std::string word){ return length(word); }).as_dynamic() .flat_map([=](int length){ return times("hoge", length); }).as_dynamic() .flat_map([=](std::string word) { return twice(word); }).as_dynamic(); ob.subscribe([=](std::string word) { std::cout << word << std::endl; }); }
チュートリアル
一番簡単な使い方
rxcpp::observable<int> obs = rxcpp::observable<>::create<int> ( [=](rxcpp::subscriber<int> s) { s.on_next(100); s.on_next(200); s.on_next(300); s.on_completed(); } ); auto x = obs.flat_map([=](int x) { return rxcpp::observable<>::just(x * 1000); }).as_dynamic() .flat_map([=](int x) { return rxcpp::observable<>::just("hoge"); }).as_dynamic(); auto l = x.subscribe([=](std::string txt){ std::cout << txt << std::endl; }); std::async(std::launch::async, [l]() { usleep(5*1000*1000); std::cout << "**unsubscribe**" << std::endl; l.unsubscribe(); });
variant 共用体
かなり便利なことがわかった。
#include <boost/variant.hpp> #include <iostream> int main(int argc, const char * argv[]) { // insert code here... std::cout << "Hello, World!\n"; boost::variant<int, std::string> v; v = 100; boost::variant<int, std::string> s; s = "200"; if (v.type() == typeid(int)) { int l = boost::get<int>(v); std::cout << l + 1000 << std::endl; int* k = boost::get<int>(&v); std::cout << *k + 2000 << std::endl; } return 0; }
チュートリアル的な記述7
typeerase的なものを作ってみたがポインタ周りが怪しいので修正中
#include "TypeErase.hpp" #include <iostream> #include <map> class AnyBase; using AnyBase_sp = std::shared_ptr<AnyBase>; class AnyBase { public: AnyBase() = default; virtual ~AnyBase() = default; template<typename T> T get(); static AnyBase_sp make(std::string x); static AnyBase_sp make(int x); }; template <typename T> class Any; template <typename T> using Any_sp = std::shared_ptr<Any<T>>; template <typename T> class Any : public AnyBase { public: Any(std::string x) : hold(x){}; Any(int x): hold(x){}; ~Any() {}; T hold; static Any_sp<T> make(std::string x) { auto r = std::make_shared<Any<T>>(x); return r; } }; template <typename T> T AnyBase::get() { return dynamic_cast<Any<T>*>(this)->hold; } AnyBase_sp AnyBase::make(std::string x) { auto a = std::make_shared<Any<decltype(x)>>(x); return a; } AnyBase_sp AnyBase::make(int x) { auto a = std::make_shared<Any<decltype(x)>>(x); return a; } class Storage { public: Storage() = default; ~Storage() = default; }; void useTypeTrace() { AnyBase_sp xx = AnyBase::make("xxxxx"); AnyBase_sp yy = AnyBase::make(33333); // std::cout << "typeErase " << x->get<int>() << std::endl; std::cout << "typeErase " << xx->get<std::string>() << std::endl; std::cout << "typeErase " << yy->get<int>() << std::endl; }
チュートリアル的な記述6
継承やテンプレートなどを色々使ってみた。
#include <iostream> void hello() { std::cout << "hello/bye" << std::endl; std::string s; while (true) { std::cin >> s; if (s == "hello") { std::cout << "hello!" << std::endl; } else if (s == "bye") { std::cout << "bye!" << std::endl; } else { std::cout << "?" << std::endl; } } } class Name { public: std::string name; Name(std::string name) { this->name = name; } }; template <typename T> class EchoSkill { public: void echo(T x); }; template <> void EchoSkill<std::string>::echo(std::string x) { std::cout << "echo: " << x << std::endl; } template <> void EchoSkill<int>::echo(int x) { std::cout << "echo int: " << x << std::endl; } class Counter : public Name, public EchoSkill<int>, public EchoSkill<std::string> { public: Counter(std::string name) : Name(name) { } ~Counter(){} void count() { countNum++; } int getCount() { return countNum; } private: int countNum = 0; }; std::string question(std::string txt) { std::string s; std::cout << txt << std::endl; std::cin >> s; return s; } void hello2() { typedef std::shared_ptr<Counter> Counter_sptr; auto counter = std::make_shared<Counter>("hoge"); while (true) { std::string s = question("hello/bye/repCount/name"); if (s == "hello") { std::cout << "hello! " << counter->name <<"." << std::endl; counter->count(); } else if (s == "bye") { counter->EchoSkill<std::string>::echo("bye!"); break; } else if (s == "name") { counter->name = question("input name"); } else if (s == "repCount") { counter->EchoSkill<int>::echo(counter->getCount()); } else { std::cout << "?" << std::endl; } } }
チュートリアル的な記述5
クラス、構造体
// class デフォルトのアクセス指定子がprivate // struct デフォルトのアクセウ指定子がpublic struct Animal; struct Man2; struct Animal { int age = 10; virtual void attack(); }; struct Man2 : Animal { typedef std:: shared_ptr<std::string> string_ptr; string_ptr name_ptr; Man2(std::string name); ~Man2(); static void staticFunc(); void hello(); void func1() &; // void func1() &&; // 右辺値参照の際 void constFunction() const; }; Man2::Man2(std::string name) { this->name_ptr = std::make_shared<std::string>(name); } Man2::~Man2() { } void Man2::staticFunc() { std::cout << "staticFunc" << std::endl; } void Man2::hello() { std::cout << "hello" << std::endl; } void Man2::func1() & { std::cout << "func1 &" << std::endl; } void Man2::func1() && { std::cout << "func1 &&" << std::endl; } void Man2::Animal::attack() { std::cout << "attack" << std::endl; } void useMan2() { auto man2 = new Man2("aaa"); int a = man2->age; Man2::staticFunc(); man2->staticFunc(); man2->hello(); man2->func1(); Man2("cddd").func1(); }
チュートリアル的な記述4
ファイル操作
#include <iostream> #include <fstream> void fileSample() { // file std::ofstream ofs("test.txt"); if (!ofs) { std::cerr << "[error]open file" << std::endl; std::exit(1); } ofs << "Hello, World\n123" << std::endl; // auto close std::ifstream ifs("test.txt"); if (!ifs) { std::cerr << "[error]open file for ifstream." << std::endl; std::exit(1); } std::string bufstr; ifs >> bufstr; std::cout << bufstr << std::endl; //[note] output is Hello, std::ifstream ifs2("test.txt"); if (!ifs2) { std::cerr << "[error]open file for ifstream." << std::endl; std::exit(1); } std::string bufstr2; getline(ifs2, bufstr2); std::cout << bufstr2 << std::endl; //[note] output is Hello, World getline(ifs2, bufstr2); std::cout << bufstr2 << std::endl; //[note] output is 123 if (ifs2.eof()) { std::cout << "eof" << std::endl; //[note] output is 123 } }
チュートリアル的な記述3
変数
#include <sstream> #include <iomanip> #include <fstream> void basicVariable() { const int c = 10; // ref int r = 0; int& r2 = r; r2 = 100; std::cout << r << std::endl; // 100 // 構造体 Point p; p.x = 10; p.y = 10; std::cout << p.d2() <<std::endl; // enum // enum ColorType1 type1 = ColorType1::RED; ColorType2 type2 = ColorType2::RED; ColorType3 type3 = ColorType3::RED; ColorType1 type4 = RED; // ColorType2 type5 = RED; できない // ColorType3 type6 = RED; できない std::cout << type1 << std::endl; std::cout << static_cast<int>(type2) << std::endl; std::cout << static_cast<int>(type3) << std::endl; std::cout << type4 << std::endl; // auto 型推論 auto x = "x"; // 文字列 std::string z = "ac"; auto y = 3.0; auto z1 = z + z; auto z2 = x + z; auto z3 = z + x; std::string z5 = z.append(x); // acx std::string z6 = z.append(z); // acxacx z.empty();// empty check //auto z4 = x + x; //できない。 const char* std::cout << x << std::endl; std::cout << y << std::endl; std::cout << z << std::endl; // acxacx std::cout << z5 << std::endl;// acx std::cout << z6 << std::endl;// acxacx // decltype int sample = 100; decltype(sample) sample2 = 200; // Type of sample2 is Int. decltype(getValue()) sample3 = 3.3;// Type of sample3 is Int. std::cout << sample << sample2 << sample3 << std::endl; // escape std::string stresc = "a\nb\nc"; std::string stresc2 = R"(a b c)"; std::cout << stresc << std::endl; std::cout << stresc2 << std::endl; // null pointer int* a = nullptr; if (a == nullptr) { std::cout << "nullptr" << std::endl; } }
文字列
#include <iostream> void stringUse() { std::string x = "aaa"; std::string y = "bbb"; std::string z = x + y; std::cout << z << std::endl; }
ベクトル
#include <iostream> #include <vector> void vectorUse() { std::vector<int> v = {1,5,10,100}; v[2] = 100; v.push_back(50); /// もっと簡単に表示してしたい for (int x: v) { std::cout << x << std::endl; } std::vector<int> v2 = {1,3,2,5}; /// +は使えないのだろうか。 C++にカテゴリ拡張はない。 v2.insert(v2.end(), v.begin(), v.end()); /// coutが面倒だ。。 std::cout << "v2" << std::endl; for (int x: v2) { std::cout << x << std::endl; } }