宏語法
// TODO 預處理器不是編譯器,預處理器主要完成文本替換的操作(文本替換,以後專門在Linux中去講),預處理器都是用 #xxx 的寫法,並不是註釋哦
/*
#include 導入頭文件
#if if判斷操作 【if的範疇 必須endif】
#elif else if
#else else
#endif 結束if
#define 定義一個宏
#ifdef 如果定義了這個宏 【if的範疇 必須endif】
#ifndef 如果沒有定義這個宏 【if的範疇 必須endif】
#undef 取消宏定義
#pragma 設定編譯器的狀態
*/
#include <iostream>
using namespace std;
int main() {
// std::cout << "宏" << std::endl;
#if 1 // if
cout << "真" << endl;
#elif 0 // else if
cout << "假" << endl;
#else
cout << "都不滿足" << endl;
#endif // 結束if
cout << "結束if" << endl;
return 0;
}
宏定義 解決循環拷貝的問題
#ifndef CLIONCPPPROJECT_T2_H // 如果沒有定義這個宏 解決循環拷貝的問題
#define CLIONCPPPROJECT_T2_H // 我就定義這個宏
// 100 行代碼
// 第一次能夠進來
// 第二次 第n此進不來 直接 解決循環拷貝的問題了
// ---------------
#ifndef isRelease // 如果沒有isRelease這個宏
#define isRelease 1 // 是否是正式環境下 【我就定義isRelease這個宏】
#if isRelease == true
#define RELEASE // 正式環境下 定義RELEASE宏
#elif isRelease == false
#define DEBUG // 測試環境下 定義DEBUG宏
#endif // 結束裏面的if
#endif // 結束裏面的if
#endif //CLIONCPPPROJECT_T2_H // 結束外面的if
#include <iostream>
#include "T2.h"
using namespace std;
int main() {
// if 條件判斷
// ifdef xxx 是否定義了xxx這個宏
#ifdef DEBUG // 是否定義了DEBUG這個宏
cout << "在測試環境下,迭代功能" << endl;
// 省略 500行 ...
#else RELEASE
cout << "在正式環境下,功能上下中" << endl;
// 省略 500行 ...
#endif // 結束IF
}
宏的取消 #undef 宏
// 宏的取消 #undef 宏
#include <iostream>
using namespace std;
int main() {
int i = 1
#ifndef DERRY // 如果沒有定義這個宏
#define DERRY // 我就定義宏
#ifdef DERRY // 是否定義了這個宏
for (int i = 0; i < 6; ++i) {
cout << "Derry 1" << endl;
}
// 省略 500行 ...
#ifdef DERRY // 是否定義了這個宏
for (int i = 0; i < 6; ++i) {
cout << "Derry 2" << endl;
}
// 省略 500行 ...
#undef DERRY // 取消宏的定義,下面的代碼,就沒法用這個宏了,相當於:沒有定義過DERRY宏
#ifdef DERRY
cout << "你定義了Derry宏" << endl;
#else
cout << "你沒有定義了Derry宏" << endl;
#endif
#endif
#endif
#endif
return 0;
}
宏變量 真實開發中:宏都是大寫
#include <iostream>
using namespace std;
#define VALUE_I 9527
#define VALUE_S "AAA"
#define VALUE_F 545.3f
int main() {
int i = VALUE_I; // 預處理階段 宏會直接完成文本替換工作,替換後的樣子:int i = 9527;
string s = VALUE_S; // 預處理階段 宏會直接完成文本替換工作,替換後的樣子:string s = "AAA";
float f = VALUE_F; // 預處理階段 宏會直接完成文本替換工作,替換後的樣子:float f = 545.3f;
return 0;
}
宏函數 優缺點
#include <iostream>
using namespace std;
#define SHOW(V) cout << V << endl; // 參數列表 無需類型 返回值 看不到
#define ADD(n1, n2) n1 + n2
#define CHE(n1, n2) n1 * n2 // 故意製作問題 ,宏函數的注意事項
// 複雜的宏函數 宏函數要 \ 才能換行
#define LOGIN(V) if(V==1) { \
cout << "滿足 你個貨輸入的是:" << V << endl; \
} else { \
cout << "不滿足 你個貨輸入的是:" << V << endl; \
} // 這個是結尾,不需要加 \
void show() {}
int main() {
SHOW(8);
SHOW(8.8f);
SHOW(8.99);
int r = ADD(1, 2);
cout << r << endl;
r = ADD(1+1, 2+2);
cout << r << endl;
// r = CHE(1+1, 2+2);
r = 1+1 * 2+2; // 文本替換:1+1 * 2+2 先算乘法 最終等於 5
cout << r << endl; // 我們認爲的是8, 但是打印5
LOGIN(0);
LOGIN(0);
LOGIN(0);
LOGIN(0);
LOGIN(0);
LOGIN(0);
// 會導致代碼體積增大
show();
show();
show();
show();
show();
// 普通函數,每次都會進棧 彈棧 ,不會導致代碼體積增大
return 0;
}
// 宏函數
/*
* 優點:
* 1.文本替換,不會造成函數的調用開銷(開闢棧空間,形參壓棧,函數彈棧釋放 ..)
*
* 缺點:
* 1.會導致代碼體積增大
*
*/
jni函數詳解
#include "com_derry_as_jni_project_MainActivity.h"
// NDK工具鏈裏面的 log 庫 引入過來
#include <android/log.h>
#define TAG "Derry"
// ... 不知道傳入什麼? 藉助JNI裏面的宏來自動幫我填充
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
// extern "C": 必須採用C的編譯方式,爲什麼,請看JNIEnv內部源碼
// // 無論是C還是C++ 最終是調用到 C的JNINativeInterface,所以必須採用C的方式 extern "C"
// 函數的實現
extern "C"
JNIEXPORT // 標記該方法可以被外部調用(VS上不加入 運行會報錯, AS上不加入運行沒有問題)
// Linux運行不加入,不報錯, Win 你必須加入 否則運行報錯, MacOS 還不知道
jstring // Java <---> native 轉換用的
JNICALL // 代表是 JNI標記,可以少
// Java_包名_類名_方法名 ,注意:我們的包名 _ native _1
// JNIEnv * env JNI:的橋樑環境 300多個函數,所以的JNI操作,必須靠他
// jobject jobj 誰調用,就是誰的實例 MainActivity this
// jclass clazz 誰調用,就是誰的class MainActivity.class
Java_com_derry_as_1jni_1project_MainActivity_getStringPwd
(JNIEnv * env, jobject jobj) {
}
// 靜態函數
extern "C"
JNIEXPORT jstring JNICALL
Java_com_derry_as_1jni_1project_MainActivity_getStringPwd2(JNIEnv *env, jclass clazz) {
// TODO: implement getStringPwd2()
}
extern "C"
JNIEXPORT void JNICALL
Java_com_derry_as_1jni_1project_MainActivity_changeName(JNIEnv *env, jobject thiz) {
// 獲取class
jclass j_cls = env->GetObjectClass(thiz);
// 獲取屬性 L對象類型 都需要L
// jfieldID GetFieldID(MainActivity.class, 屬性名, 屬性的簽名)
jfieldID j_fid = env->GetFieldID(j_cls, "name", "Ljava/lang/String;");
// 轉換工作
jstring j_str = static_cast<jstring>(env->GetObjectField(thiz ,j_fid));
// 打印字符串 目標
char * c_str = const_cast<char *>(env->GetStringUTFChars(j_str, NULL));
LOGD("native : %s\n", c_str);
LOGE("native : %s\n", c_str);
LOGI("native : %s\n", c_str);
// 修改成 Beyond
jstring jName = env->NewStringUTF("Beyond");
env->SetObjectField(thiz, j_fid, jName);
// printf() C
// cout << << endl; // C++
}
extern "C"
JNIEXPORT void JNICALL
Java_com_derry_as_1jni_1project_MainActivity_changeAge(JNIEnv *env, jclass jcls) {
const char * sig = "I";
jfieldID j_fid = env->GetStaticFieldID(jcls, "age", sig);
jint age = env->GetStaticIntField(jcls, j_fid);
age += 10;
env->SetStaticIntField(jcls, j_fid, age);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_derry_as_1jni_1project_MainActivity_callAddMethod(JNIEnv *env, jobject job) {
// 自己得到 MainActivity.class
jclass mainActivityClass = env->GetObjectClass(job);
// GetMethodID(MainActivity.class, 方法名, 方法的簽名)
jmethodID j_mid = env->GetMethodID(mainActivityClass, "add", "(II)I");
// 調用 Java的方法
jint sum = env->CallIntMethod(job, j_mid, 3, 3);
LOGE("sum result:%d", sum);
}
package com.derry.as_jni_project;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
// 生成頭文件:javah com.derry.as_jni_project.MainActivity
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
public static final int A = 100;
public String name = "Derry"; // 簽名:Ljava/lang/String;
public static int age = 29; // 簽名:I
// Java 本地方法 實現:native層
public native String getStringPwd();
public static native String getStringPwd2();
// ------------- 交互操作 JNI
public native void changeName();
public static native void changeAge();
public native void callAddMethod();
// 專門寫一個函數,給native成調用
public int add(int number1, int number2) {
return number1 + number2 + 8;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
changeName();
tv.setText(name);
changeAge();
tv.setText("" + age);
callAddMethod();
}
}
簽名規則 大寫
/*
javap -s -p MainActivity 必須是.class
Java的boolean --- Z 注意點
Java的byte --- B
Java的char --- C
Java的short --- S
Java的int --- I
Java的long --- J 注意點
Java的float --- F
Java的double --- D
Java的void --- V
Java的引用類型 --- Lxxx/xxx/xx/類名;
Java的String --- Ljava/lang/String;
Java的array int[] --- [I double[][][][] --- [[[D
int add(char c1, char c2) ---- (CC)I
void a() === ()V
javap -s -p xxx.class -s 輸出xxxx.class的所有屬性和方法的簽名, -p 忽略私有公開的所有屬性方法全部輸出
*/