Android Jni添加打印(C++打印)

Android Jni添加打印(C++打印)

文章目录

  • Android Jni添加打印(C++打印)
    • 一、前言
    • 二、添加日志实现
      • 1、在某个类上面定义类型和方法
      • 2、把日志方法定义在.h文件中
      • 定义 myLog.h
      • 3、引用打印头文件的示例代码
        • (1) MainActivity.java 代码
        • (2) 另外一个cpp代码类和头文件
        • (3)jni native-lib.cpp代码类
        • (4)打印内容
    • 三、其他
      • 1、打印各种类型和示例
        • (1)整数类型:
        • (2)浮点数类型:
        • (3)字符类型:
        • (4)字符串类型:
        • (5)布尔类型:
      • 2、日志打印不出情况
      • 3、__android_log_write 和 __android_log_print 区别?
        • (1)参数形式:
        • (2)使用方式:

一、前言

Android Jni中添加日志打印其实就是C/C++日志打印

Android环境的C/C++代码打印,可以添加相关头文件后,调用打印方法

跟Android打印类似,也是有打印级别,I,D,W,E

二、添加日志实现

1、在某个类上面定义类型和方法

网上一般做法,在某一个cpp类的上面写如下代码:

#include <android/log.h> //添加头文件
#define LOG_TAG "TstCPlus" //定义TAG
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

在方法中使用即可:

 LOGI("test");int result = 100;LOGI("test result = %d", result);

其他级别打印也是同理使用。

上面的方法把定义都写在打印的定义都写在一个类里面了,如果多个类使用打印就不方便了,

如果要多个类都能见到调用到就可以定义在.h头文件里面,其他类加入定义一下头文件调用到了。

2、把日志方法定义在.h文件中

定义 myLog.h

#include <android/log.h>#define LOG_TAG "TestCPlus"
#define ANDROID_PLATFORM#ifdef ANDROID_PLATFORM#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))#else#define LOGD(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)#define LOGI(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)#define LOGW(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)#define LOGE(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#endif
#endif

上面代码添加了是否Android平台的判断,如果觉得没必要可以直接去掉。

DEBUG的值也可以设置成false,0就是false。

在具体cpp文件中,可以重新定义TAG标签

#include "myLog.h"
#define LOG_TAG "TAG_NAME"

3、引用打印头文件的示例代码

(1) MainActivity.java 代码
    String TAG = "MainActivity Java";static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.i(TAG, "onCreate");TextView tv = findViewById(R.id.sample_text);tv.setText(stringFromJNI());}public native String stringFromJNI();
(2) 另外一个cpp代码类和头文件
//TestCPlus.cpp 代码
#include "TestCPlus.h"
#include "Androidlog.h"int TestCPlus::add(int parameter1, int parameter2) {int result = parameter1 + parameter2;LOGI("MainActivity jni c++ result = %d", result);//添加打印,但是没有定义TAGreturn result;
}//TestCPlus.h头文件代码
class TestCPlus {
//定义变量和方法
private:int number;
public:int add(int parameter1,int parameter2); //定义方法
};
(3)jni native-lib.cpp代码类
#include <jni.h>
#include <string>#include "Androidlog.h"
#include "TestCPlus.h"
#define LOG_TAG "native-lib.cpp" //重新定义TAGextern "C" JNIEXPORT jstring JNICALL
Java_com_demo_jnilog_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {std::string hello = "Hello from C/C++";LOGD("MainActivity jni c++ ");int num= 100;LOGI("MainActivity jni c++ ,num = %d", num);TestCPlus *testCPlus;int result =  testCPlus->add(2, 50);LOGI("MainActivity jni c++ ,result = %d", result);return env->NewStringUTF(hello.c_str());
}
(4)打印内容
2024-02-29 15:07:40.706  I/MainActivity Java: onCreate
2024-02-29 15:07:40.706  D/native-lib.cpp: MainActivity jni c++ 
2024-02-29 15:07:40.706  I/native-lib.cpp: MainActivity jni c++ ,num = 100
2024-02-29 15:07:40.706  I/TestLog: MainActivity jni c++ result = 52
2024-02-29 15:07:40.706  I/native-lib.cpp: MainActivity jni c++ ,result = 52

可以看到未定义 LOG_TAG 的 TestCPlus.cpp文件打印的就是使用原本的TAG,定义了的,就是用新的TAG

三、其他

1、打印各种类型和示例

在C++中,可以使用不同的格式化输出来打印各种数据类型。下面是一些常见的数据类型及其对应的打印格式:

(1)整数类型:
 int: 使用"%d"格式打印,例如:`int num = 10; printf("%d", num);`long: 使用"%ld"格式打印,例如:`long num = 1000000; printf("%ld", num);`short: 使用"%hd"格式打印,例如:`short num = 5; printf("%hd", num);`
(2)浮点数类型:
 float: 使用"%f"格式打印,例如:`float num = 3.14; printf("%f", num);`double: 使用"%lf"格式打印,例如:`double num = 2.71828; printf("%lf", num);`
(3)字符类型:
char: 使用"%c"格式打印,
例如:`char ch = 'A'; printf("%c", ch);`
(4)字符串类型:
char数组或指针:使用"%s"格式打印,
例如:`char str[] = "Hello"; printf("%s", str);`
参数的里面的jstring打印示例:
Java_com_example_example_NativeClass_printString(JNIEnv* env, jobject obj, jstring str) {const char* nativeString = env->GetStringUTFChars(str, NULL);if (nativeString != NULL) {LOGI("String from Java: %s\n", nativeString);env->ReleaseStringUTFChars(str, nativeString);//或者:std::string hello = "Hello from C++";LOGI("stringFromJNI hello = %s", hello.c_str());}
}
(5)布尔类型:
bool: 使用"%d"或"%s"格式打印,分别将true打印为1,false打印为0或者"true"和"false",
例如:`bool flag = true; printf("%d", flag);`

上面的打印printf在Android平台打印都替换成 LOGI 即可。

以上是一些常见数据类型的打印方式,你可以根据具体需要选择合适的格式化输出来打印不同的数据类型。

2、日志打印不出情况

如果在JNI的CPP文件中日志打印不出来,可能有以下几个原因:

1. 缺少日志打印库:在CPP文件中,需要包含头文件 ``,并且使用 Android NDK 提供的日志库函数来进行打印。
请确保你的CPP文件中正确包含了该头文件。2. 编译配置问题:在编译时,需要将日志库链接到你的JNI库中。
在 Android.mk 或 CMakeLists.txt 文件中,确保添加了正确的链接库配置。
示例:`LOCAL_LDLIBS += -llog`。3. 日志级别设置问题:检查你的日志打印语句中的日志级别参数,
例如 `__android_log_print(ANDROID_LOG_DEBUG, "TAG", "Log message");`。
确保日志级别设置正确,以便在运行时打印出来。4. 运行时过滤问题:在 Android Logcat 中,可能需要设置正确的过滤条件,以确保你的日志能够显示出来。
请确保你在 Logcat 中设置了正确的标签过滤条件,以及你期望的日志级别过滤条件。

如果以上步骤都确认无误,但仍然无法打印日志,可以检查一下日志打印语句是否被执行到,或者尝试在其他位置打印日志,以确定是否是特定位置的问题。另外,确保你的应用具有适当的权限来写入日志。

如果问题仍然存在,建议提供更多的代码细节或错误信息,以便更好地理解问题并提供帮助。

3、__android_log_write 和 __android_log_print 区别?

两个方法都是log.h里面定义的方法,目前看,两种方式都是可以打印,但是区别有什么呢

在Android的JNI开发中,__android_log_write__android_log_print都是用于在native代码中打印日志的函数。它们的区别如下:

(1)参数形式:
 `__android_log_write`函数的参数形式为:`__android_log_write(int prio, const char *tag, const char *msg)`。其中,`prio`表示日志的优先级,`tag`表示日志的标签,`msg`表示日志的内容。`__android_log_print`函数的参数形式为:`__android_log_print(int prio, const char *tag, const char *fmt, ...)`。其中,`prio`和`tag`的含义与`__android_log_write`相同,而`fmt`是一个格式化字符串,后面可以是可变参数。

第一种方式比较接近Java代码的打印,msg字符串里面要包含所有打印的信息。

第二种就是c++的打印方式,可以输入多个参数。在cpp文件中一般都是使用第二种。

(2)使用方式:
 `__android_log_write`函数需要将日志内容作为字符串传入,可以直接调用该函数输出,例如:`__android_log_write(ANDROID_LOG_DEBUG, "TAG", "Log message");``__android_log_print`函数使用类似于`printf`函数的格式化字符串,可以传入多个参数,例如:`__android_log_print(ANDROID_LOG_DEBUG, "TAG", "Log message: %d", value);`

总的来说,__android_log_write函数更直接,适合简单的日志输出;

__android_log_print函数更灵活,可以使用格式化字符串来输出带有变量值的日志信息。

实际使用中,可以根据需要选择合适的函数来打印日志。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/717674.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【详识JAVA语言】面向对象程序三大特性之三:多态

多态 多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 多态实现条件 在java中要实现多态&#xff0c;必须要满足如下几个条件&#xff0c;缺一不可&#xf…

循环队列与循环双端队列

文章目录 前言循环队列循环双端队列 前言 1、学习循环队列和循环双端队列能加深我们对队列的理解&#xff0c;提高我们的编程能力。 2、本文循环队列使用的是数组&#xff0c;循环双端队列用的是双向链表 3、题目连接&#xff1a;设计循环队列 &#xff0c;设计循环双端队列。 …

【机器学习】有监督学习算法之:支持向量机

支持向量机 1、引言2、决策树2.1 定义2.2 原理2.3 实现方式2.4 算法公式2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c;泡澡啊。 小鱼&#xff1a;不去 小屌丝&#xff1a;… 此话当真&#xff1f; 小鱼&#xff1a;此话不假 小屌丝&#xff1a;到底去还是…

Linux 网络接口的混杂模式(Promiscuous mode)认知

写在前面 博文内容为 混杂模式的简单认知理解不足小伙伴帮忙指正 认定一件事&#xff0c;即使拿十分力气都无法完成&#xff0c;也要拿出十二分力气去努力。 —《剑来》 网络接口的混杂模式 混杂模式(Promiscuous mode)&#xff0c;简称 Promisc mode&#xff0c;俗称监听模式…

什么是支持向量机(Support vector machine)和其原理

作为机器学习的基础算法&#xff0c;SVM被反复提及&#xff0c;西瓜书、wiki都能查到详细介绍&#xff0c;但是总是觉得还差那么点&#xff0c;于是决定自己总结一下。 一、什么是SVM&#xff1f; 1、解决什么问题&#xff1f; SVM&#xff0c;最原始的版本是用于最简单的线…

蓝桥杯备赛第五篇(动态规划)

1.数位dp public class Main {static long[] limit;static int length;static long[][] dp;public static long dfs(int pos, int pre, boolean flag, boolean lead) {if (pos length) return 1;if (!flag && !lead && dp[pos][pre] ! -1) return dp[pos][pr…

总结 HashTable, HashMap, ConcurrentHashMap 之间的区别

1.多线程环境使用哈希表 HashMap 不行,线程不安全 更靠谱的,Hashtable,在关键方法上加了synchronized 后来标准库又引入了一个更好的解决方案;ConcurrentHashMap 2.HashMap 首先HashMap本身线程不安全其次HashMap的key值可以为空&#xff08;当key为空时&#xff0c;哈希会…

【Java数据结构】——五道算法题让你灵活运用Map和Set

目录 一.只出现一次的数字 二.宝石与石头 三.旧键盘 四.给定一个数组&#xff0c;统计每个元素出现的次数 五.前K个高频单词 一.只出现一次的数字 136. 只出现一次的数字 - 力扣&#xff08;LeetCode&#xff09; 算法原理&#xff1a;我们将nums中每个元素都存入到set中…

C/C++嵌入式开发环境搭建,Qt交叉编译,cmake交叉编译,clion/vscode远程开发

目录 交叉编译简介cmake 交叉编译clion 交叉编译vscode 远程嵌入式开发Qt交叉编译1.安装交叉编译工具2.交叉编译qt库3.将交叉编译的Qt库复制到板子上4.安装和配置 Qt Creator&#xff0c;支持交叉编译5.QT嵌入式开发6.QT嵌入式开发报错解决QIconvCodec::convertToUnicode: usin…

ASUS华硕天选5笔记本电脑FX607JV原装出厂Win11系统下载

ASUS TUF Gaming F16 FX607JV天选五原厂Windows11系统 适用型号&#xff1a; FX607JU、FX607JI、FX607JV、 FX607JIR、FX607JVR、FX607JUR 下载链接&#xff1a;https://pan.baidu.com/s/1l963wqxT0q1Idr98ACzynQ?pwd0d46 提取码&#xff1a;0d46 原厂系统自带所有驱动、…

TypeScript中 “ <> “ 语法 和 “ : “ 怎么使用

在 TypeScript 中&#xff0c;尖括号语法(<Type>)和as关键字(value as Type)都是用于类型断言&#xff0c;而冒号(:)用于类型注解。这三种语法在不同的场景下使用&#xff1a; 尖括号语法和as关键字&#xff1a; 尖括号语法(<Type>value)&#xff1a; 这种语法在…

[LeetBook]【学习日记】链表反转

来源于「Krahets」的《图解算法数据结构》 https://leetcode.cn/leetbook/detail/illustration-of-algorithm/ 链表反转的递归要点 递归终止条件为当前节点为空&#xff0c;表明遍历到了链表尾部递归函数传入参数为当前节点的下一个节点按照是否重新开辟存储空间分类下面只写…

python自动化学习--3.8python操作EXCEL文件python日志收集处理

1、Excel文件处理 安装 openpxl 第三方库 openpxl 模块三大组件: 1、工作簿 &#xff08;包含多个sheet工作表&#xff09; 2、工作表 &#xff08;某个数据包含在某个工作表&#xff09; 3、单元格 1、创建excel工作簿 import openpyxl"""Excel表格的创建…

【简说八股】Spring事务失效可能是哪些原因?

Spring事务介绍 Spring事务是指在Spring框架中对数据库操作进行管理的一种机制&#xff0c;它确保一组数据库操作要么完全执行成功&#xff08;提交&#xff09;&#xff0c;要么完全不执行&#xff08;回滚&#xff09;&#xff0c;从而保持数据一致性和完整性。 Spring框架…

GotoXy控制台光标的位置更新

光标控制解释 控制台的光标更新方法, 用于控制数据输出位置 void gotoXY(int x, int y)//新函数&#xff1a;更新光标 {COORD c;c.X x;c.Y y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c); }代码解释 这段代码定义了一个名为 gotoXY 的函数&#xff0c;…

设计模式-装饰者模式应用实践

装饰者模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许动态地向一个现有的对象添加新的功能&#xff0c;同时不改变其结构。这种模式通过创建一个装饰类来包装原有的类&#xff0c;提供额外的行为。 下面是一个使用 Java 实现装饰者模式…

【Spring Boot】实现全局异常处理

1.定义基础异常接口类 /*** description: 服务接口类* author: MrVK* date: 2021/4/19 21:39*/ public interface BaseErrorInfoInterface {/*** 错误码* return*/String getResultCode();/*** 错误描述* return*/String getResultMsg(); } 2.定义错误处理枚举类 /*** desc…

小伙伴询问AI该怎么学习?本人的一点总结,以思维导图呈现

如有需要思维导图的在后台请留邮箱&#xff0c;相关知识结构目录 部分导图

nn.Linear() 使用提醒

原本以为它是和nn.Conv2d()一样&#xff0c;就看第二个维度的数值&#xff0c;今天才知道&#xff0c;它是只看最后一个维度的数值&#xff01;&#xff01;&#xff01; 例子1 Descripttion: Result: Author: Philo Date: 2024-02-27 14:33:50 LastEditors: Philo LastEditT…

git使用merge命令把dev分支的mian.js文件和src下面的vuex文件夹以及config文件夹单独合并到master分支上

使用 git merge 命令来单独合并特定文件或文件夹到另一个分支通常不是最直接的方法&#xff0c;因为 merge 命令是用来合并两个分支的所有更改的。然而&#xff0c;你可以通过 git cherry-pick 命令或者通过创建临时补丁&#xff08;patch&#xff09;来实现这一点。 下面是一个…