jni/C/C++ 筆記

Android Studio 編譯原生庫(kù)的默認(rèn)編譯工具是 CMake姨蟋。
由于很多現(xiàn)有項(xiàng)目都使用 ndk-build 編譯工具包,因此 Android Studio 也支持 ndk-build吉拳。
不過(guò),如果您要?jiǎng)?chuàng)建新的原生庫(kù),則應(yīng)使用 CMake胎围。

CMake 構(gòu)建腳本是一個(gè)純文本文件,您必須將其命名為 CMakeLists.txt

CMake 使用以下規(guī)范來(lái)為庫(kù)文件命名:
lib庫(kù)名稱.so

CMakeLists 命令
指定Cmake的最小版本
cmake_minimum_required(VERSION 3.4.1)

設(shè)置項(xiàng)目名稱
project(xxxx)

add_library( xxx //生成的文件名
STATIC/SHARED // STATIC 生成靜態(tài)庫(kù) SHARED生產(chǎn) 動(dòng)態(tài)或共享庫(kù)
xxx.cpp //指定包含哪些源文件
xxxx.cpp
)

find_library(VAR name path) 查找到指定的預(yù)編譯庫(kù)德召,并將它的路徑存儲(chǔ)在變量中白魂,默認(rèn)的搜索路徑為Cmake包含的系統(tǒng)庫(kù),因此NDK的公共庫(kù)上岗,只需要指定庫(kù)的name即可福荸。

target_link_libraries{
xxx //目標(biāo)庫(kù)

// 目標(biāo)庫(kù)需要連接的庫(kù) 這里是find_library指定的變量名
${xxxx}
}

_cplusplus 為C++關(guān)鍵字 表示作用域內(nèi)的代碼為C++ 代碼
extern "C" 為了保證C++和C是互通的

c語(yǔ)言不能直接引用聲明了 extern "C" 的 C++ 頭文件,需要聲明其為外部函數(shù)

JNI基礎(chǔ)知識(shí)

普通調(diào)用定義接口 : 可以在多個(gè)類中被調(diào)用
定向調(diào)用定義接口: 僅能在特定的java類中被調(diào)用

普通調(diào)用定義接口 動(dòng)態(tài)注冊(cè)
基本思想: 在調(diào)用System.loadLibrary的時(shí)候液茎,會(huì)在C/C++ 文件中回調(diào)一個(gè)名為JNI_OnLoad()的函數(shù)逞姿,
在該函數(shù)里通過(guò)JNI提供的RegisterNatives()方法來(lái)將C/C++ 方法和java方法對(duì)應(yīng)起來(lái)

JNI 接口定義 -> JNI接口映射 -> 注冊(cè)JNI接口映射 -> 設(shè)置在共享庫(kù)加載時(shí) JNI接口映射
1.編寫(xiě)Java的native方法和C/C++的實(shí)現(xiàn)方法
2.通過(guò)方法簽名信息 將java方法和C/C++ 方法一一對(duì)應(yīng)
3.實(shí)現(xiàn)JNI_Onliad()方法
3.1.通過(guò)JavaVM 獲取JNIENV
3.2.使用類名和對(duì)應(yīng)起來(lái)的方法作為參數(shù),調(diào)用JNI提供的函數(shù)RegisterNatives() 注冊(cè)方法

typedef struct {
const char* name;
const char* signature;
void* fnPtr; //函數(shù)指針捆等,指向native函數(shù)滞造。前面都要接 (void *)
} JNINativeMethod;

JNI簽名:
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
void v;
jbooleanArray [Z;
jintArray [i;
jlongArray [J;
jdoubleArray [d;
jfloatArray [f;
jbyteArray [b;
jcharArray [c;
jshortArray [s;
jobject L完整包名加類名 ;
} jvalue;

例子

傳入的java參數(shù)有兩個(gè) 分別是 int 和 long[] 函數(shù)返回值為 String 即函數(shù)的定義為:String getString(int a ,long[] b)
簽名就應(yīng)該是 :"(I[J)Ljava/lang/String;"(不要漏掉英文分號(hào))
如果有內(nèi)部類 則用 來(lái)分隔 如:Landroid/os/FileUtilsFileStatus;

總結(jié) :
當(dāng)熟悉動(dòng)態(tài)注冊(cè)后, 動(dòng)態(tài)注冊(cè)無(wú)疑是注冊(cè)函數(shù)的更好方式, 唯一要注意的是注冊(cè)函數(shù)時(shí), 需要額外小心,
別把類名,函數(shù)名和簽名寫(xiě)錯(cuò)了, 不然loadLibraries時(shí)會(huì)導(dǎo)致應(yīng)用Crash

JNI調(diào)用java方法的過(guò)程
findClass -> GetMethodId(獲取java方法的句柄) -> Call*Method(調(diào)用java方法)

JNI操作java變量的一般過(guò)程
FindClass -> GetFieldId(獲取java變量的句柄) -》GetField/SetFieldId 操作java變量

jobject代表了在java端調(diào)用本地c/c++代碼的那個(gè)類的一個(gè)實(shí)例(對(duì)象)
jclass : 為了能夠在c/c++中使用java類JNI.h頭文件中專門(mén)定義了jclass類型來(lái)表示java中的Class類

libthread
創(chuàng)建線程函數(shù)

mutex 互斥鎖 mutex_ -> lock()/ mutex_->unlock()

<cstdio> cstdio是將stdio.h的內(nèi)容用C++頭文件的形式表示出來(lái)。stdio.h是C標(biāo)準(zhǔn)函數(shù)庫(kù)中的頭文件
且cstdio中的函數(shù)都是定義在一個(gè)名稱空間std里面的栋烤,如果要調(diào)用這個(gè)名字空間的函數(shù)谒养,必須得加std::或者在文件中聲明using namespace std

在C++中, 如果的構(gòu)造函數(shù)只有一個(gè)參數(shù)時(shí), 那么在編譯的時(shí)候就會(huì)有一個(gè)缺省的轉(zhuǎn)換操作:將該構(gòu)造函數(shù)對(duì)應(yīng)數(shù)據(jù)類型的數(shù)據(jù)轉(zhuǎn)換為該類對(duì)象
C++ explicit 只能用于修飾只有一個(gè)參數(shù)的類構(gòu)造函數(shù),表該構(gòu)造函數(shù)時(shí)顯示的,而非隱式的买窟。 類構(gòu)造函數(shù)默認(rèn)即聲明為 implicit(隱式)

左結(jié)合
相當(dāng)于有兩個(gè)連續(xù)的同一優(yōu)先級(jí)的運(yùn)算符時(shí)左邊運(yùn)算符加了圓括號(hào)丰泊。
右結(jié)合
相當(dāng)于有兩個(gè)連續(xù)的同一優(yōu)先級(jí)的運(yùn)算符時(shí)右邊運(yùn)算符加了圓括號(hào)。

C++ 中的冒號(hào)(:)用法
(1)表示機(jī)構(gòu)內(nèi)位域的定義(即該變量占幾個(gè)bit空間)

typedef struct _XXX{

unsigned char a:4;

unsigned char c;

} ; XXX

(2)構(gòu)造函數(shù)后面的冒號(hào)起分割作用始绍,是類給成員變量賦值的方法瞳购,初始化列表,更適用于成員變量的常量const型亏推。

struct _XXX{

_XXX() : y(0xc0) {}

};
3) public:和private:后面的冒號(hào)学赛,表示后面定義的所有成員都是公有或私有的,直到下一個(gè)"public:”或"private:”出現(xiàn)為止吞杭。"private:"為默認(rèn)處理盏浇。

(4)類名冒號(hào)后面的是用來(lái)定義類的繼承。

class 派生類名 : 繼承方式 基類名

{

派生類的成員

};

繼承方式:public芽狗、private和protected绢掰,默認(rèn)處理是public。

雙冒號(hào)(::)的用法

1童擎、
作用域符號(hào)::的前面一般是類名稱滴劲,后面一般是該類的成員名稱,C++為例避免不同的類有名稱相同的成員而采用作用域的方式進(jìn)行區(qū)分
如:A,B表示兩個(gè)類顾复,在A,B中都有成員member哑芹。那么
A::member就表示類A中的成員member
B::member就表示類B中的成員member

2、
全局作用域符號(hào):當(dāng)全局變量在局部函數(shù)中與其中某個(gè)變量重名捕透,那么就可以用::來(lái)區(qū)分如:

char zhou; //全局變量

void sleep()

char zhou; //局部變量

char(局部變量) = char(局部變量) *char(局部變量) ;

::char(全局變量) =::char(全局變量) *char(局部變量);

3聪姿、
::是C++里的“作用域分解運(yùn)算符”。比如聲明了一個(gè)類A乙嘀,類A里聲明了一個(gè)成員函數(shù)voidf()末购,但沒(méi)有在類的聲明里給出f的定義,那么在類外定義f時(shí)虎谢,就要寫(xiě)成voidA::f()盟榴,表示這個(gè)f()函數(shù)是類A的成員函數(shù)

c++ 中的 static_cast和dynamic_cast運(yùn)用于繼承關(guān)系類間的強(qiáng)制轉(zhuǎn)化

static_cast< new_type >(expression)
dynamic_cast< new_type >(expression)
備注:new_type為目標(biāo)數(shù)據(jù)類型,expression為原始數(shù)據(jù)類型變量或者表達(dá)式婴噩。

static_cast相當(dāng)于傳統(tǒng)的C語(yǔ)言里的強(qiáng)制轉(zhuǎn)換擎场,該運(yùn)算符把expression轉(zhuǎn)換為new_type類型,
用來(lái)強(qiáng)迫隱式轉(zhuǎn)換如non-const對(duì)象轉(zhuǎn)為const對(duì)象几莽,編譯時(shí)檢查迅办,用于非多態(tài)的轉(zhuǎn)換,
可以轉(zhuǎn)換指針及其他章蚣,但沒(méi)有運(yùn)行時(shí)類型檢查來(lái)保證轉(zhuǎn)換的安全性站欺。它主要有如下幾種用法:

①用于類層次結(jié)構(gòu)中基類(父類)和派生類(子類)之間指針或引用的轉(zhuǎn)換。
進(jìn)行上行轉(zhuǎn)換(把派生類的指針或引用轉(zhuǎn)換成基類表示)是安全的;
進(jìn)行下行轉(zhuǎn)換(把基類指針或引用轉(zhuǎn)換成派生類表示)時(shí)矾策,由于沒(méi)有動(dòng)態(tài)類型檢查磷账,所以是不安全的。
②用于基本數(shù)據(jù)類型之間的轉(zhuǎn)換贾虽,如把int轉(zhuǎn)換成char逃糟,把int轉(zhuǎn)換成enum。
③把空指針轉(zhuǎn)換成目標(biāo)類型的空指針蓬豁。
④把任何類型的表達(dá)式轉(zhuǎn)換成void類型履磨。
注意:static_cast不能轉(zhuǎn)換掉expression的const、volatile庆尘、或者_(dá)_unaligned屬性

盡量少使用轉(zhuǎn)型操作,尤其是dynamic_cast巷送,耗時(shí)較高驶忌,會(huì)導(dǎo)致性能的下降,盡量使用其他方法替代

c/c++ 中的可變參數(shù) va系列解釋

是采用宏定義來(lái)實(shí)現(xiàn)

#ifndef _VA_LIST
typedef __builtin_va_list va_list;
#define _VA_LIST
#endif
#define va_start(ap, param) __builtin_va_start(ap, param)
#define va_end(ap)          __builtin_va_end(ap)
#define va_arg(ap, type)    __builtin_va_arg(ap, type)

/* GCC always defines __va_copy, but does not define va_copy unless in c99 mode
 * or -ansi is not specified, since it was not part of C90.
 */
#define __va_copy(d,s) __builtin_va_copy(d,s)

va_list 定義了一個(gè)指針ap, 用于指示可選的參數(shù)

va_start(ap, param)
使 參數(shù)列表指針arg_ptr指向函數(shù)參數(shù)列表中的第一個(gè)可選參數(shù)
param 是位于第一個(gè)可選參數(shù)之前的固定參數(shù)

va_end(ap)
清空參數(shù)列表, 并置參數(shù)指針ap無(wú)效.

va_arg(ap, type)
返回參數(shù)列表中指針ap所指的參數(shù), 返回類型為type. 并使指針ap指向參數(shù)列表中下一個(gè)參數(shù).返回的是可選參數(shù), 不包括固定參數(shù).

例子:

void AndroidLog::log(const char *fmt, ...) {
    Lock fileLock(&mutex_);
    if(!fmt){
        return;
    }
    if (fp_ || openFile()){
        va_list vp;
        va_start(vp,fmt);
        vfprintf(fp_,fmt,vp);
        va_end(vp);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笑跛,一起剝皮案震驚了整個(gè)濱河市付魔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌飞蹂,老刑警劉巖几苍,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異陈哑,居然都是意外死亡妻坝,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)惊窖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刽宪,“玉大人,你說(shuō)我怎么就攤上這事界酒∈ブ簦” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵毁欣,是天一觀的道長(zhǎng)庇谆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)凭疮,這世上最難降的妖魔是什么饭耳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮执解,結(jié)果婚禮上哥攘,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好逝淹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布耕姊。 她就那樣靜靜地躺著,像睡著了一般栅葡。 火紅的嫁衣襯著肌膚如雪茉兰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天欣簇,我揣著相機(jī)與錄音规脸,去河邊找鬼。 笑死熊咽,一個(gè)胖子當(dāng)著我的面吹牛莫鸭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播横殴,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼被因,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了衫仑?” 一聲冷哼從身側(cè)響起梨与,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎文狱,沒(méi)想到半個(gè)月后粥鞋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞄崇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年呻粹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苏研。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尚猿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出楣富,到底是詐尸還是另有隱情凿掂,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布纹蝴,位于F島的核電站庄萎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏塘安。R本人自食惡果不足惜糠涛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望兼犯。 院中可真熱鬧忍捡,春花似錦集漾、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至凌埂,卻和暖如春驱显,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瞳抓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工埃疫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人孩哑。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓栓霜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親横蜒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胳蛮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355