NDK-以十六进制字符串的形式打印char[]数组到logcat

发布时间 2023-12-26 17:49:29作者: 夜行过客

NDK-以十六进制字符串的形式打印char[]数组到logcat

1. 在Java中打印

public static String convertByteArr2String(byte[] bArr) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < bArr.length; i++) {
        builder.append(String.format(Locale.getDefault(), "%02x", bArr[i]).toUpperCase()).append(" ");
    }
    return builder.toString();
}

2. 在C语言中打印

在 Android NDK 开发中,需要使用 __android_log_print 函数来输出日志信息。这个函数是 Android NDK 的日志系统的一部分,类似于 Java 中的 Log 类。要使用它,你需要包含头文件 <android/log.h>

以下是一个示例,展示如何使用 __android_log_print 在 NDK 中打印一个 char 数组的十六进制表示:

#include <android/log.h>
#include <stdio.h>

#define LOG_TAG "MyTag"

void printHex(const char* arr, int length) {
    char buffer[3 * length + 1]; // 每个字节最多占用3个字符(两个十六进制字符和一个空格)加上终止字符
    char *ptr = buffer;

    for (int i = 0; i < length; i++) {
        ptr += sprintf(ptr, "%02X ", arr[i]);
    }

    __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Hex string: %s", buffer);
}

int main() {
    char arr[] = {0x1a, 0x2b, 0x3c, 0x4d};  // 示例数组
    int length = sizeof(arr) / sizeof(arr[0]);  // 计算数组长度

    printHex(arr, length);

    return 0;
}

这个代码定义了一个 printHex 函数,它接受一个 char 数组和它的长度,然后构建一个包含数组十六进制表示的字符串。sprintf 函数用于将每个数组元素转换为十六进制格式。最后,使用 __android_log_print 将构建好的十六进制字符串输出到日志中。

要注意的是,你需要在你的 NDK 项目中正确配置 Android.mkApplication.mk 文件,以便包含和链接 Android 的日志库。如果使用的是CMake,需要在 target_link_libraries中添加日志库的引用:

target_link_libraries(
        my-jni-lib
        log # 必须
)

3. 关于sprintf()函数

3.1 是否需要在输出的字符串末尾添加 '\0'结束符?

在上面的例子中:

for (int i = 0; i < length; i++) {
        ptr += sprintf(ptr, "%02X ", arr[i]);
}

__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Hex string: %s", buffer);

在格式化字符串后,直接使用 __android_log_print()函数对log进行了输出,那是否需要在buffer的字符串末尾添加 \0结束符呢?我们知道C语言字符串的末尾是需要以\0结束的,用于标识字符串结束。

答案是不需要的。原因在于:

在上述代码中,使用 sprintf 函数时,每次调用都会自动在生成的字符串末尾添加一个空字符(\0),作为字符串的终止符。因此,在迭代完整个数组后,buffer 数组的最后一个元素已经是由 sprintf 在其最后一次调用时自动添加的空字符。

这意味着在循环结束后,你不需要显式地将 buffer 数组的最后一个字节置为 0,因为 sprintf 已经为你处理了这个问题。每次 sprintf 被调用时,它都会在写入数据的末尾添加一个 \0 字符,确保了字符串是正确终止的。

根据 C 语言的标准,sprintf 函数在向目标字符串写入内容后,总是会在末尾自动添加一个空字符('\0'),作为字符串的结束标志。这是 C 语言中所有标准字符串函数的通用行为:字符串总是以空字符结束。

当你使用 sprintf 或类似函数(如 snprintfstrcpystrcat 等)时,它们会在完成字符串操作后,在字符串的末尾添加一个 '\0'。这确保了字符串是正确终止的,使其成为一个合法的 C 字符串。因此,在使用这些函数处理字符串时,你需要确保有足够的空间来容纳所有字符,包括终止的空字符。

3.2 p+= sprintf(), 这里加的值是几?指针每次偏移多少?

在上述例子中的 ptr += sprintf(ptr, "%02x ", arr[i]); 表达式里,sprintf 函数的返回值是它写入 ptr 指向的字符串的字符数(注意不包括终止的空字符 \0)。对于格式 %02x

  • %02x 会产生两个字符,代表一个字节的十六进制表示。
  • 空格 ' ' 会产生一个额外的字符。

因此,对于每个数组元素,sprintf 将产生 3 个字符(两个十六进制数字和一个空格)。所以,ptr 每次会向前移动 3 个字符的位置。

假设 arr[i]0x1A,那么 sprintf(ptr, "%02x ", arr[i]); 会在 ptr 指向的位置写入 "1a ",然后返回 3,表示写入了 3 个字符。之后,ptr 就会向前移动 3 个位置,准备下一次的写入。

<完>