2023年1月26日 星期四

java Native 調用 C

public class TestNative {
    public native void helloNative1();
    public static native void helloNative2();

    static {
        System.load(System.getProperty("user.dir") + "/xxx.dll");
    }

    public static void main(String[] args) {
        new TestNative().helloNative1();
        TestNative.helloNative2();
    }
}

※System.getProperty("user.dir") 為專案路徑
※xxx.dll 為 c 的程式碼變成的


產生 dll 的方法:
1.到 TestNative.java 打上 javac TestNative.java -h .
會產生副檔名為 h 和 class 的檔案

2.將副檔名為 h 的檔案複製一份出來改檔名為 cpp,完成後為如下的圖:


3.修改 cpp 檔案的內容,這個就是要實作 native 的內容

#include <jni.h>
#include <stdio.h>
#include "TestNative.h"

JNIEXPORT void JNICALL Java_TestNative_helloNative1
  (JNIEnv *, jobject) {
  printf("%s", "helloNative1\n");
  }

JNIEXPORT void JNICALL Java_TestNative_helloNative2
  (JNIEnv *, jclass) {
  printf("%s", "helloNative2\n");
  }

※要 include TestNative.h

4.到 sourceforge.net 下載 c 的編譯器 MinGW-w64,然後如下下載,並解壓



5.進入解壓後的資料夾的 bin
打上 gcc --version,出現版本號表示可以用 gcc 這個指令了
再打上 gcc -I "C:\Program Files\Java\jdk1.8.0_202\include" -I "C:\Program Files\Java\jdk1.8.0_202\include\win32" --shared -o xxx.dll D:\JavaProject\src\TestNative.cpp
會產生 xxx.dll 的檔案

※-I 表示 include,要包含兩個檔案,因為 3 的檔案要用到 jni.h,這個檔案在 include 裡;然後 jni.h 這個檔案還要 include jni_md.h,這個檔案在 include\win32

※-o 為 output,後面接想輸出的檔案名稱

※最後是 cpp 所在路徑

6.將得到的 xxx.dll 放在專案路徑下即可,其他 cpp、h 都可以不需要,結果畫面如下:










2023年1月9日 星期一

C語言指針

 線上測試

※基本型態指針

// 包括 short int long float double chat

#include <stdio.h>

void test(int *d)  {

    *d = 100; // 將 d 這個位址對應的值,改成 100; 寫 d 或 &d 都會報錯

}


int main() {

    int digit = 2;

    test(&digit);

    printf("digit=%d", digit);

    return 0;

}


在變數前加上 &,表示傳的是記憶體位址;

    在變數前加上 *,表示接收記憶體位址

    所以可以這樣宣告變數 int *x = &digit;   test(x);

※這樣的好處是方法裡改變的值,會影響調用方的值

※只有傳的時候給 &,接收時給 * 才不會報錯,其他都會報錯



※陣列指針

#include <stdio.h>


int main() {

    int arr[] = {1, 2, 3};


    // 注意是用 int *p 來接,不是 int[]*p,會報錯

    int *p = arr; // 指向的是 arr[0]的記憶體位址,陣列不可打 &arr,因為它有多個值,要傳其中一個值可用 &arr[0],但代表整體就不能有 &,會報錯

    

    // 以下三個結果一樣

    printf("%p\n", &arr[0]);

    printf("%p\n", arr);

    printf("%p\n", p);

    

    // 以下三個結果一樣,和上面差 4,也就是 4 Bytes

    printf("%p\n", &arr[1]);

    printf("%p\n", arr + 1);

    printf("%p\n", p + 1);

    

    // 以下三個結果都是 2,也就是取值

    printf("%d\n", *(&arr[1]));

    printf("%d\n", *(arr + 1));

    printf("%d\n", *(p + 1));

    

    printf("%p\n", &arr + 1); // &arr 是整個 arr 的記憶體位址,如果佔用 4Bytes,結果將是 4Bytes 結束再 + 1,可用 sizeof() 查看佔多少 Byte

    return 0;

}



※字串指針

int main() {

    char *p = "a";

    printf("string=%s", p);

    

    // int *i = 9;

    // printf("digit=%d", i);

    return 0;

}

※字串指針可以直接賦值,其他不行


※陣列裡放指針

int main() {

    char *s1 = "ab";

    char *s2 = "cd";

    char *s3 = "ef";

    

    char *s[3] = {s1, s2, s3}; // 和陣列就差一個 *,只有字串可以這樣寫

    printf("string=%p\n", s);

    printf("%s", s[1]);


    return 0;

}