public class NDKCInterface {
public native void executeCConst();
}
public class NDKCppInterface {
//1.学习C++中的常量(包括和C中的常量的区别)
public native void executeCppConst();
//2.C++指针的引用
public native void executeCppPointer();
//3.C++常引用
public native void executeCppConstRef();
//4.C++内联函数
public native void executeCppInlineFunc();
//5.C++函数参数
public native void exceuteCppFuncParam();
//6.C++函数指针
public native void exceuteCppFuncPointer();
//7.C++中的类的定义
public native void executeCppClass();
}
com_tz_ndk_cpp_NDKCInterface.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_tz_ndk_cpp_NDKCInterface */
#ifndef _Included_com_tz_ndk_cpp_NDKCInterface
#define _Included_com_tz_ndk_cpp_NDKCInterface
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_tz_ndk_cpp_NDKCInterface
* Method: executeCConst
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCInterface_executeCConst
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <android/log.h>
#include "com_tz_ndk_cpp_NDKCInterface.h"
//C语言中常量是否可以修改
//C语言中也不能修改
//总结:常量的值在C语言中是可以修改的,但是与编译的环境有关系
//例如:在android studio中不可以,在Visual Studio 2013就可以修改
//然而C++语言不管在任何的编译环境中都是不允许修改
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCInterface_executeCConst
(JNIEnv *env, jobject jobj){
const int a = 100;
int *p = (int*)&a;
*p = 200;
__android_log_print(ANDROID_LOG_INFO,"main","C语言:%d",a);
}
com_tz_ndk_cpp_NDKCppInterface.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_tz_ndk_cpp_NDKCppInterface */
#ifndef _Included_com_tz_ndk_cpp_NDKCppInterface
#define _Included_com_tz_ndk_cpp_NDKCppInterface
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_tz_ndk_cpp_NDKCppInterface
* Method: executeCppConst
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppConst
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppPointer
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppConstRef
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppInlineFunc
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_exceuteCppFuncParam
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_exceuteCppFuncPointer
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppClass
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
com_tz_ndk_cpp_NDKCppInterface.cpp
#include <iostream>
#include <android/log.h>
#include "com_tz_ndk_cpp_NDKCppInterface.h"
//在C++中命名空间(类似于Java的包)
//std:代表标准命名空间
using namespace std;
//C++中常量
//C++中常量的值不能够修改(不管你是间接修改还是直接修改,都不是不允许)
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppConst
(JNIEnv *env, jobject jobj){
const int a = 100;
//常量不能修改
// a = 200;
//间接修改
int *p = (int*)&a;
*p = 200;
__android_log_print(ANDROID_LOG_INFO,"main","修改值:%d",a);
}
//2.指针的引用
struct User{
char *name;
int age;
};
//二级指针
//void update_user(User** u){
// User *user = (User*)malloc(sizeof(User));
// user->name = "Dream";
// user->age = 100;
// *u = user;
//}
//指针的引用
//&u代表是User地址(相当于引用)
void update_user(User* &u){
u = (User*)malloc(sizeof(User));
u->name = "Crish";
u->age = 18;
}
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppPointer
(JNIEnv *env, jobject jobj){
User *user = NULL;
//二级指针的使用
// int a = 100;
// int *p = &a;
// int **p2 = &p;
// update_user(&user);
// __android_log_print(ANDROID_LOG_INFO,"main","result: %s",user->name);
//指针的引用
int a = 100;
// (int*) p = &a;
//编译器自动将 user转成&user
update_user(user);
__android_log_print(ANDROID_LOG_INFO,"main","result: %s",user->name);
}
//C++中的常引用(初始化方式)
void const_init(){
int a = 100;
int b = 200;
//第一种写法:变量赋值
//常引用写法:const int &c
//引用:&c
//我们这么写: int &c = a;
//int &c = a;等价int* c = &a;
//编译器:int* c = &a;
const int &c = a;
__android_log_print(ANDROID_LOG_INFO,"main","变量赋值:%d",c);
//第二种写法:字面量
const int &d = 200;
__android_log_print(ANDROID_LOG_INFO,"main","字面量: %d\n",d);
}
//重点是:常引用作为函数的参数使用
struct Company{
char *name;
char *address;
int age;
};
//类似于Java中的final(只读)
void const_func_param(const Company &cp){
//不能修改(只读)
// cp.age = 100;
__android_log_print(ANDROID_LOG_INFO,"main","公司地址: %s",cp.address);
}
void const_printf(){
Company company;
company.address = "湖南省芯城科技园10栋";
company.name = "潭州教育科技有限公司";
company.age = 10;
const_func_param(company);
}
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppConstRef
(JNIEnv *env, jobject jobj){
// const_init();
const_printf();
}
//4.内联函数(inline)
//在程序编译的时候,编译器将函数调用处的代码替换成函数体
//内联函数:编译的时候调用
//宏定义:预编译
//例如:买书
//买书之前准备钱(预编译)
//找书店过程(编译)
//找到了书店,买书(运行)
//在使用上面和普通的函数没什么区别,但是执行的效率比一般的函数要高
inline void printf_inline(){
char *address = "Dream";
__android_log_print(ANDROID_LOG_INFO,"main","内容:%s",address);
}
//宏定义和内联函数的区别?
//需求:求一个数的积?
//总结:这两种情况一般情况都不要这么写(自增、自减)
#define GET_RESULT(A) A*A
inline int get_result(int a){
return a * a;
}
void printf_result(){
int a = 2;
//宏函数预编译替换
//分析:int b = (++a) * (++a)
//第一次加:a = 3 * (++a)
//第二次加:a = 4
//结果: 3 * 4 = 12;
// int b = GET_RESULT(++a);
//内联函数(和普通的方法一样)
//结果:a * a ,然而a = 3 结果:9
int b = get_result(++a);
__android_log_print(ANDROID_LOG_INFO,"main","结果:%d",b);
}
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppInlineFunc
(JNIEnv *env, jobject jobj){
//拷贝(编译的时候)
// {
// char *address = "Dream";
// __android_log_print(ANDROID_LOG_INFO,"main","内容:%s",address);
// }
// printf_inline();
printf_result();
}
//5.C++中函数参数
//函数参数默认值
//void func_param(int a = 100){
// __android_log_print(ANDROID_LOG_INFO,"main","result: %d",a);
//}
//函数重载(在Java中方法重载:参数个数,参数类型不同,与返回值无关)
//总结:定义函数重载需要注意不能够存在函数"歧义"
//void func_param(int a){
// __android_log_print(ANDROID_LOG_INFO,"main","result: %d",a);
//}
//void func_param(int a,int b = 10){
// __android_log_print(ANDROID_LOG_INFO,"main","result: a=%d, b=%d",a,b);
//}
//b默认值,后面的参数必须设置默认值
//void func_param(int a,int b){
// __android_log_print(ANDROID_LOG_INFO,"main","result: %d",a);
//}
//void func_param(int a,int b = 10,int c = 10,int d = 100){
// __android_log_print(ANDROID_LOG_INFO,"main","result: %d",a);
//}
//C++中函数可变参数
//API都会提示用户传参数类型
void func_param(int a,...){
__android_log_print(ANDROID_LOG_INFO,"main","result: %d",a);
//获取可变参数
//定义可变参数指针
va_list args_p;
//首先指定可变参数开始位置
va_start(args_p,a);
//一个个获取(按照顺序读取)
//第一个参数int类型
int arg_int = va_arg(args_p,int);
__android_log_print(ANDROID_LOG_INFO,"main","第一个参数: %d",arg_int);
//第二个参数char类型
char arg_char = va_arg(args_p,char);
__android_log_print(ANDROID_LOG_INFO,"main","第二个参数: %c",arg_char);
//第三个参数double类型
double arg_float = va_arg(args_p, double);
__android_log_print(ANDROID_LOG_INFO,"main","第三个参数: %f",arg_float);
//结束
va_end(args_p);
}
//循环读取(一般情况下都是指定类型)
//注意:必须要指定一个可变参数开始位置
void func_param_int(int a,int len,...){
//定义可变参数指针
va_list args_p;
//首先指定可变参数开始位置
va_start(args_p,len);
int i = 0;
int result = 0;
for(;i < len ;i++){
result = va_arg(args_p,int);
__android_log_print(ANDROID_LOG_INFO,"main","参数: %d",result);
}
// int i = 0;
// while (true){
// i = va_arg(args_p,int);
// if(i == 0){
// //告诉程序读取完毕
// break;
// }
// __android_log_print(ANDROID_LOG_INFO,"main","参数: %d",i);
// }
//结束
va_end(args_p);
}
//函数预留参数(提高了程序扩展性)
void func_param(int a,int){
__android_log_print(ANDROID_LOG_INFO,"main","参数: %d",a);
}
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_exceuteCppFuncParam
(JNIEnv *env, jobject jobj){
// func_param();
// func_param(10);
// func_param(10,20);
//歧义?
// func_param(10);
// func_param(10,20);
// func_param(10,40,'A',45.3);
// func_param_int(10,5,20,30,40,50,60);
func_param(10,20);
}
//6.函数指针
int get_min(int a,int b,int c,int d){
return a < b ? a : b;
}
//函数指针别名
typedef int(*GET_MIN_P)(int,int,int,int);
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_exceuteCppFuncPointer
(JNIEnv *env, jobject jobj){
//函数指针
// int(*get_min_p)(int,int,int,int) = get_min;
// int c = get_min_p(10,20,20,30);
// __android_log_print(ANDROID_LOG_INFO,"main","最小值: %d",c);
GET_MIN_P p = get_min;
int result = p(10,20,30,40);
__android_log_print(ANDROID_LOG_INFO,"main","最小值: %d",result);
}
//7.C++中的类的定义
#include "Computer.h"
JNIEXPORT void JNICALL Java_com_tz_ndk_cpp_NDKCppInterface_executeCppClass
(JNIEnv *, jobject){
// Computer computer;
//
// computer.setCPU("Inter");
// computer.setDisplay("独立显卡");
// computer.setName("Macbook Pro 2016款");
// computer.setAge(6);
// __android_log_print(ANDROID_LOG_INFO,"main","显卡: %s",computer.getDisplay());
//也可以new
Computer* computer = new Computer();
computer->setAge(100);
computer->setDisplay("独立显卡");
__android_log_print(ANDROID_LOG_INFO,"main","显卡: %s",computer->getDisplay());
}
Computer.h
//这个判断就是为了避免重复include
#ifndef DREAM_NDK_CPP_11_3_COMPUTER_H
#define DREAM_NDK_CPP_11_3_COMPUTER_H
//申明该类
class Computer{
private:
char *cpu;
char *display;
char *name;
int age;
public:
void setCPU(char* cpu);
char* getCPU();
void setDisplay(char* display);
char* getDisplay();
void setName(char *name);
char* getName();
void setAge(int age);
int getAge();
};
#endif //DREAM_NDK_CPP_11_3_COMPUTER_H
Computer.cpp
#include <iostream>
#include "Computer.h"
void Computer::setCPU(char *cpu) {
this->cpu = cpu;
}
char *Computer::getCPU() {
return this->cpu;
}
void Computer::setDisplay(char *display) {
this->display = display;
}
char *Computer::getDisplay() {
return this->display;
}
void Computer::setName(char *name) {
this->name = name;
}
char *Computer::getName() {
return this->name;
}
void Computer::setAge(int age) {
this->age = age;
}
int Computer::getAge() {
return this->age;
}
activity:
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
private NDKCppInterface cppInterface;
private NDKCInterface cInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cppInterface = new NDKCppInterface();
cInterface = new NDKCInterface();
String a = new String("Dream");
get(a,10,30,200,300);
}
private void get(String s,int... a){
s = "100";
}
public native String stringFromJNI();
public void clickCppConst(View v){
cppInterface.executeCppConst();
}
public void clickCConst(View v){
cInterface.executeCConst();
}
public void clickCppPointer(View v){
cppInterface.executeCppPointer();
}
public void clickCppConstRef(View v){
cppInterface.executeCppConstRef();
}
public void clickCppInlineFunc(View v){
cppInterface.executeCppInlineFunc();
}
public void clickCppFuncParam(View v){
cppInterface.exceuteCppFuncParam();
}
public void clickCppFuncPointer(View v){
cppInterface.exceuteCppFuncPointer();
}
public void clickCppClass(View v){
cppInterface.executeCppClass();
}
}
配置文件:CMakeLists.txt
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/native-lib.cpp
src/main/cpp/com_tz_ndk_cpp_NDKCppInterface.cpp
src/main/cpp/com_tz_ndk_cpp_NDKCInterface.c
src/main/cpp/Computer.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
整理自示例代码