Android NDK 允許將 C/C++ 程式碼編譯為原生共享庫(.so),透過 JNI (Java Native Interface) 供 Java/Kotlin 呼叫。適用於:效能關鍵路徑、既有 C/C++ 庫移植、跨平台核心邏輯共用、繞過 Java 層限制。本文為兩部分系列的第一部分,涵蓋 C 基礎語法、資料類型、指標、記憶體管理、編譯流程。
#include
#include
int main(void) {
printf("Hello, NDK World!\n");
system("pause"); // Windows 專用,Linux/Android 不需要
return 0;
}
| 類型 | 大小 | 格式符 | 備註 |
|---|---|---|---|
| char | 1 byte | %c / %hhd | 有號性實作定義 |
| short | 2 bytes | %hd | |
| int | 4 bytes | %d | |
| long | 4/8 bytes | %ld | 32/64 位不同 |
| long long | 8 bytes | %lld | C99 |
| float | 4 bytes | %f | |
| double | 8 bytes | %lf | |
| void * | 4/8 bytes | %p | 指標 |
關鍵差異:Java char 2 bytes (UTF-16),C char 1 byte;Java 無 unsigned,C 有 unsigned int 等;C 無 boolean,非 0 為真。
int a; scanf("%d", &a); // 掃描整數
char buf[100]; fgets(buf, sizeof(buf), stdin); // 讀整行
printf("a=%d, buf=%s", a, buf);
&var 取變數地址;*ptr 解引用(存取地址指向的值)。int *p = &a;:p 儲存 a 的地址,*p 等價於 a。僅對連續記憶體(陣列)有意義:
int arr[5] = {1,2,3,4,5};
int *p = arr; // 指向首元素
printf("%d\n", *(p+2)); // 3,等價 arr[2]
printf("%td\n", (p+2) - p); // 2,元素個數差
指標減法結果為元素個數差,非位元組差。
int a = 10;
int *p = &a;
int **pp = &p;
int ***ppp = &pp;
printf("%d\n", ***ppp); // 10
int add(int x, int y) { return x+y; }
int (*fp)(int, int) = add;
printf("%d\n", fp(3,5)); // 8
| 特性 | 棧 | 堆 |
|---|---|---|
| 分配方式 | 編譯器自動 | 程式設計師手動 malloc/free |
| 大小限制 | ~2MB (Linux 預設) | 虛擬記憶體上限 (GB 級) |
| 速度 | 極快 (指標遞增) | 較慢 (鏈表搜尋) |
| 生命週期 | 函數返回自動釋放 | 手動釋放直到 free |
| 碎片 | 無 | 易產生 |
#include
int *p = malloc(10 * sizeof(int)); // 分配
int *p2 = calloc(10, sizeof(int)); // 分配並歸零
p = realloc(p, 20 * sizeof(int)); // 擴容/縮容,內容保留
free(p); p = NULL; // 釋放並防懸空指標
void alloc_array(int **out, int n) {
*out = malloc(n * sizeof(int));
}
int main() {
int *arr;
alloc_array(&arr, 10); // 傳指標的指標
free(arr);
}
struct Student { char sex; int age; float score; int id; };
union Data { long l; int i; char c; }; // 共用記憶體,長度取最大成員
enum WeekDay { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
typedef unsigned int uint32; // 類型別名
# 本地編譯
gcc hello.c -o hello
# Android NDK 交叉編譯 (arm64-v8a)
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang \
hello.c -o hello_arm64
# 編譯為共享庫
$NDK/.../clang -shared -fPIC hello.c -o libhello.so
關鍵概念:.c → .o (編譯) → .so/.exe (鏈接)。交叉編譯在宿主機(x86_64)產出目標架構(arm64/mips)可執行碼,需工具鏈提供目標系統的 libc、kernel headers、鏈接器。
下集將實戰演示:
CMakeLists.txt / Android.mk。native 方法。logcat 除錯。UnsatisfiedLinkError、簽名不匹配、記憶體洩漏、ANR。