jni/C/C++ 笔记

Android Studio 编译原生库的默认编译工具是 CMake。
由于很多现有项目都使用 ndk-build 编译工具包,因此 Android Studio 也支持 ndk-build。
不过,如果您要创建新的原生库,则应使用 CMake。

CMake 构建脚本是一个纯文本文件,您必须将其命名为 CMakeLists.txt

CMake 使用以下规范来为库文件命名:
lib库名称.so

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

设置项目名称
project(xxxx)

add_library( xxx //生成的文件名
STATIC/SHARED // STATIC 生成静态库 SHARED生产 动态或共享库
xxx.cpp //指定包含哪些源文件
xxxx.cpp
)

find_library(VAR name path) 查找到指定的预编译库,并将它的路径存储在变量中,默认的搜索路径为Cmake包含的系统库,因此NDK的公共库,只需要指定库的name即可。

target_link_libraries{
xxx //目标库

// 目标库需要连接的库 这里是find_library指定的变量名
${xxxx}
}

_cplusplus 为C++关键字 表示作用域内的代码为C++ 代码
extern "C" 为了保证C++和C是互通的

c语言不能直接引用声明了 extern "C" 的 C++ 头文件,需要声明其为外部函数

JNI基础知识

普通调用定义接口 : 可以在多个类中被调用
定向调用定义接口: 仅能在特定的java类中被调用

普通调用定义接口 动态注册
基本思想: 在调用System.loadLibrary的时候,会在C/C++ 文件中回调一个名为JNI_OnLoad()的函数,
在该函数里通过JNI提供的RegisterNatives()方法来将C/C++ 方法和java方法对应起来

JNI 接口定义 -> JNI接口映射 -> 注册JNI接口映射 -> 设置在共享库加载时 JNI接口映射
1.编写Java的native方法和C/C++的实现方法
2.通过方法签名信息 将java方法和C/C++ 方法一一对应
3.实现JNI_Onliad()方法
3.1.通过JavaVM 获取JNIENV
3.2.使用类名和对应起来的方法作为参数,调用JNI提供的函数RegisterNatives() 注册方法

typedef struct {
const char* name;
const char* signature;
void* fnPtr; //函数指针,指向native函数。前面都要接 (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参数有两个 分别是 int 和 long[] 函数返回值为 String 即函数的定义为:String getString(int a ,long[] b)
签名就应该是 :"(I[J)Ljava/lang/String;"(不要漏掉英文分号)
如果有内部类 则用 来分隔 如:Landroid/os/FileUtilsFileStatus;

总结 :
当熟悉动态注册后, 动态注册无疑是注册函数的更好方式, 唯一要注意的是注册函数时, 需要额外小心,
别把类名,函数名和签名写错了, 不然loadLibraries时会导致应用Crash

JNI调用java方法的过程
findClass -> GetMethodId(获取java方法的句柄) -> Call*Method(调用java方法)

JNI操作java变量的一般过程
FindClass -> GetFieldId(获取java变量的句柄) -》GetField/SetFieldId 操作java变量

jobject代表了在java端调用本地c/c++代码的那个类的一个实例(对象)
jclass : 为了能够在c/c++中使用java类JNI.h头文件中专门定义了jclass类型来表示java中的Class类

libthread
创建线程函数

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

<cstdio> cstdio是将stdio.h的内容用C++头文件的形式表示出来。stdio.h是C标准函数库中的头文件
且cstdio中的函数都是定义在一个名称空间std里面的,如果要调用这个名字空间的函数,必须得加std::或者在文件中声明using namespace std

在C++中, 如果的构造函数只有一个参数时, 那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象
C++ explicit 只能用于修饰只有一个参数的类构造函数,表该构造函数时显示的,而非隐式的。 类构造函数默认即声明为 implicit(隐式)

左结合
相当于有两个连续的同一优先级的运算符时左边运算符加了圆括号。
右结合
相当于有两个连续的同一优先级的运算符时右边运算符加了圆括号。

C++ 中的冒号(:)用法
(1)表示机构内位域的定义(即该变量占几个bit空间)

typedef struct _XXX{

unsigned char a:4;

unsigned char c;

} ; XXX

(2)构造函数后面的冒号起分割作用,是类给成员变量赋值的方法,初始化列表,更适用于成员变量的常量const型。

struct _XXX{

_XXX() : y(0xc0) {}

};
3) public:和private:后面的冒号,表示后面定义的所有成员都是公有或私有的,直到下一个"public:”或"private:”出现为止。"private:"为默认处理。

(4)类名冒号后面的是用来定义类的继承。

class 派生类名 : 继承方式 基类名

{

派生类的成员

};

继承方式:public、private和protected,默认处理是public。

双冒号(::)的用法

1、
作用域符号::的前面一般是类名称,后面一般是该类的成员名称,C++为例避免不同的类有名称相同的成员而采用作用域的方式进行区分
如:A,B表示两个类,在A,B中都有成员member。那么
A::member就表示类A中的成员member
B::member就表示类B中的成员member

2、
全局作用域符号:当全局变量在局部函数中与其中某个变量重名,那么就可以用::来区分如:

char zhou; //全局变量

void sleep()

char zhou; //局部变量

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

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

3、
::是C++里的“作用域分解运算符”。比如声明了一个类A,类A里声明了一个成员函数voidf(),但没有在类的声明里给出f的定义,那么在类外定义f时,就要写成voidA::f(),表示这个f()函数是类A的成员函数

c++ 中的 static_cast和dynamic_cast运用于继承关系类间的强制转化

static_cast< new_type >(expression)
dynamic_cast< new_type >(expression)
备注:new_type为目标数据类型,expression为原始数据类型变量或者表达式。

static_cast相当于传统的C语言里的强制转换,该运算符把expression转换为new_type类型,
用来强迫隐式转换如non-const对象转为const对象,编译时检查,用于非多态的转换,
可以转换指针及其他,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:

①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性

尽量少使用转型操作,尤其是dynamic_cast,耗时较高,会导致性能的下降,尽量使用其他方法替代

c/c++ 中的可变参数 va系列解释

是采用宏定义来实现

#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 定义了一个指针ap, 用于指示可选的参数

va_start(ap, param)
使 参数列表指针arg_ptr指向函数参数列表中的第一个可选参数
param 是位于第一个可选参数之前的固定参数

va_end(ap)
清空参数列表, 并置参数指针ap无效.

va_arg(ap, type)
返回参数列表中指针ap所指的参数, 返回类型为type. 并使指针ap指向参数列表中下一个参数.返回的是可选参数, 不包括固定参数.

例子:

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);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348