首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

Android NDK 開發入門:C 語言基礎到 JNI 實戰完整指南(上)

     編輯:關於C

前言

Android NDK 允許將 C/C++ 程式碼編譯為原生共享庫(.so),透過 JNI (Java Native Interface) 供 Java/Kotlin 呼叫。適用於:效能關鍵路徑、既有 C/C++ 庫移植、跨平台核心邏輯共用、繞過 Java 層限制。本文為兩部分系列的第一部分,涵蓋 C 基礎語法、資料類型、指標、記憶體管理、編譯流程。

C 語言基礎語法速覽

Hello World

#include 
#include 

int main(void) {
    printf("Hello, NDK World!\n");
    system("pause"); // Windows 專用,Linux/Android 不需要
    return 0;
}

基本資料類型與大小

類型大小格式符備註
char1 byte%c / %hhd有號性實作定義
short2 bytes%hd
int4 bytes%d
long4/8 bytes%ld32/64 位不同
long long8 bytes%lldC99
float4 bytes%f
double8 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

記憶體管理:堆 vs 棧

特性棧堆
分配方式編譯器自動程式設計師手動 malloc/free
大小限制~2MB (Linux 預設)虛擬記憶體上限 (GB 級)
速度極快 (指標遞增)較慢 (鏈表搜尋)
生命週期函數返回自動釋放手動釋放直到 free
碎片無易產生

動態記憶體 API

#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);
}

結構體、聯合體、列舉、typedef

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、鏈接器。

下一部分預告

下集將實戰演示:

  1. 建立 Android Studio 專案並配置 CMakeLists.txt / Android.mk。
  2. 編寫 JNI 函數對應 Java native 方法。
  3. 傳遞基本類型、字串、陣列、物件。
  4. C++ 異常轉 Java 異常、本地崩潰定位、logcat 除錯。
  5. 常見錯誤:UnsatisfiedLinkError、簽名不匹配、記憶體洩漏、ANR。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved