LoginSignup
5
0

More than 1 year has passed since last update.

JavaからC言語を呼び出す

Last updated at Posted at 2021-12-01

概要

JNAを使ってC言語を呼び出す方法をまとめました。

前準備

まず、JNAのライブラリをmavenなりbuild.sbtなりに追加します。

build.sbt
scalaVersion := "2.13.6"
libraryDependencies += "net.java.dev.jna" % "jna" % "5.9.0"
libraryDependencies += "net.java.dev.jna" % "jna-platform" % "5.9.0"

JavaからC言語を呼び出す

Hello World的なプログラム

C言語で共有ライブラリを作る

以下のようなプログラムを作成します。

hoge.c
#include <stdio.h>

void hoge() {
  printf("ほげぇ\n");
}

そして、以下のコマンドで共有ライブラリを作成します。

gcc -dynamiclib -o libhoge.dylib hoge.c

Java側の実装

Java側で以下のような実装をして、mainを実行すればOKです。

import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);

        void hoge();
    }

    public static void main(String[] args) {
        System.out.println("started");
        HogeInterface.INSTANCE.hoge();
        System.out.println("finished");
    }
}

ディレクトリツリー

.
├── build.sbt
├── hoge.c
├── libhoge.dylib
├── src
    ├── main
    │   ├── java
    │   │   └── JnaHoge.java
    │   ├── resources
    │   └── scala
    └── test
        └── scala

実行結果

sbtの場合、sbt "runMain JnaHoge"で実行できます。

作成したJnaHoge#mainを実行すると、
以下のどちらかのパターンで標準出力されるみたいです。

started
ほげぇ
finished

or

started
finished
ほげぇ

C言語で共有ライブラリを作って、Javaから呼び出すサンプルコード

下記リンクには、JNAでのC言語とJavaの型の対応が記載されています。
このリンクに書かれている型以外に、配列や構造体をJavaとCの間で受け渡せるようです。

引数なしでintの値を取得する

hoge.c
#include <stdio.h>

int getOne() {
  return 1;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);

        int getOne();
    }

    public static void main(String[] args) {
        System.out.println("started");
        int one = HogeInterface.INSTANCE.getOne();
        System.out.println(one);
        System.out.println("finished");
    }
}

JnaHoge#mainの実行結果:

started
1
finished

int型を渡してint型の値を得る

hoge.c
#include <stdio.h>

int squared(int x) {
  return x * x;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);

        int squared(int x);
    }

    public static void main(String[] args) {
        System.out.println("started");
        int squared = HogeInterface.INSTANCE.squared(4);
        System.out.println(squared);
        System.out.println("finished");
    }
}

実行結果:

started
16
finished

String型を渡してString型の値を得る

hoge.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* appendHoge(char* chars) {
  char hoge[] = "hoge";
  char* newChars = malloc(sizeof(chars) + sizeof(hoge));

  memcpy(newChars, chars, sizeof(chars));
  strcat(newChars, hoge);

  return newChars;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);

        String appendHoge(String cs);
    }

    public static void main(String[] args) {
        System.out.println("started");
        String str = HogeInterface.INSTANCE.appendHoge("xxx");
        System.out.println(str);
        System.out.println("finished");
    }
}

実行結果:

started
xxxhoge
finished

配列を渡して配列を得る

hoge.c
#include <stdio.h>

// 引数resultを戻り値として扱う
void hoge(int* nums, int* result) {
    result[0] = nums[0] * 10;
    result[1] = nums[1] * 10;
    result[2] = nums[2] * 10;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);

        void hoge(int[] array, int[] newArray);
    }

    public static void main(String[] args) {
        System.out.println("started");

        int[] array = {4, 5, 6};
        int[] newArray = new int[3];
        HogeInterface.INSTANCE.hoge(array, newArray);

        System.out.println(newArray[0]);
        System.out.println(newArray[1]);
        System.out.println(newArray[2]);
        System.out.println("finished");
    }
}

実行結果:

started
40
50
60
finished

構造体を渡してJavaのクラスを得る

hoge.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
  int age;
  char* name;
} PERSON;

PERSON* setName(PERSON *p, char* name) {
  p->name = name;
  return p;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;

public class JnaHoge {
    public interface HogeInterface extends Library {
        HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);

        @Structure.FieldOrder({"age", "name"})
        public class Person extends Structure {
            public int age;
            public String name;
        }

        Person setName(Person person, String name);
    }

    public static void main(String[] args) {
        System.out.println("started");
        HogeInterface.Person person = new HogeInterface.Person();
        HogeInterface.Person newPerson = HogeInterface.INSTANCE.setName(person, "パターソン");
        System.out.println(newPerson.name + "(" + newPerson.age + ")");
        System.out.println("finished");
    }
}

実行結果:

started
パターソン(0)
finished
5
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0