是的,NDK logcat 对此很愚蠢。有一些方法可以将 stderr/stdout 重定向到 logcat,但也有缺点(要么需要“adb shell setprop”,它仅适用于有根设备,要么需要类似 dup() 的技术,但仅为此目的创建线程并不好关于嵌入式设备的想法恕我直言,尽管您可以在下面进一步了解这种技术)。
所以我为此目的做了自己的函数/宏。这里是sn-ps。在 debug.c 中,这样做:
#include "debug.h"
#include <stdio.h>
#include <stdarg.h>
static const char LOG_TAG[] = "jni";
void android_log(android_LogPriority type, const char *fmt, ...)
{
static char buf[1024];
static char *bp = buf;
va_list vl;
va_start(vl, fmt);
int available = sizeof(buf) - (bp - buf);
int nout = vsnprintf(bp, available, fmt, vl);
if (nout >= available) {
__android_log_write(type, LOG_TAG, buf);
__android_log_write(ANDROID_LOG_WARN, LOG_TAG, "previous log line has been truncated!");
bp = buf;
} else {
char *lastCR = strrchr(bp, '\n');
bp += nout;
if (lastCR) {
*lastCR = '\0';
__android_log_write(type, LOG_TAG, buf);
char *rest = lastCR+1;
int len = bp - rest; // strlen(rest)
memmove(buf, rest, len+1); // no strcpy (may overlap)
bp = buf + len;
}
}
va_end(vl);
}
然后在 debug.h 中这样做:
#include <android/log.h>
void android_log(android_LogPriority type, const char *fmt, ...);
#define LOGI(...) android_log(ANDROID_LOG_INFO, __VA_ARGS__)
#define LOGW(...) android_log(ANDROID_LOG_WARN, __VA_ARGS__)
...
现在您只需要包含 debug.hpp 并调用 LOGI() 并缓冲类似 printf 的语义,直到遇到“\n”(或缓冲区已满)。
但这并不完美,如果调用生成的字符串比缓冲区长,它将被截断并输出。但坦率地说,在大多数情况下 1024 个字符就足够了(甚至比这还少)。无论如何,如果发生这种情况,它会输出一个警告,以便您了解它。
还要注意 vsnprintf() 不是标准的 C 语言(但它适用于 Android NDK)。我们可以使用 vsprintf() 代替(这是标准的),但它本身是不安全的。
================================================ ========================
现在对于 dup() 技术,您可以查看 here(James Moore 答案)。
然后你可以摆脱上面的函数并将你的宏定义为:
#define LOG(...) fprintf(stderr, ...)
你就完成了。
优点:
- C/C++ 库通常使用 stderr 作为其日志。使用 dup 是在不修改代码的情况下在 logcat 中输出的唯一方法(一些大公司使用数百次直接调用 fprintf(stderr, ...))
- stderr 是几十年来一直使用的标准 C。所有与流相关的标准 C 库函数都可以与它一起使用。对于 C++,你甚至可以将 cerr 与
- 很长的行没有被截断(相反,它们被分割了)。使用较短缓冲区(示例中为 256)的充分理由。
缺点:
- 一个单独的线程(虽然它是一个仅 IO 线程,但影响几乎没有)
- 在通话期间不能选择日志优先级值(INFO、WARN、ERROR 等...)。它使用默认值 (INFO),因此 DMMS 将始终以相同颜色显示标准错误线。