I have C code that uses prints with something clever like
printf("hello ");
// do something
printf(" world!\n");
which outputs
hello world!
I want to reuse that code with Android and iOS, but Log.d() and NSLog() effectively add a newline at the end of every string I pass them, so that the output of this code:
NSLog(@"hello ");
// do something
NSLog(@"world!\n");
comes out (more or less) as:
hello
world!
I'm willing to replace printf with some macro to make Log.d and NSLog emulate printf's handling of '\n'; any suggestions?
Yes, the NDK logcat is dumb about it. There are ways to redirect stderr/stdout to logcat, but there are drawbacks (either need to "adb shell setprop" which is only for rooted devices, or a dup() like technique but creating a thread just for that purpose is not a good idea on embedded devices IMHO though you can look further below for this technique).
So I did my own function/macros for that purpose. Here are snippets. In a debug.c, do this:
#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);
}
Then in debug.h do this:
#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__)
...
Now you just need to include debug.hpp and call LOGI() with a printf-like semantic buffered until a '\n' is encountered (or buffer is full).
This is not perfect though, as if the string generated from a call is longer than the buffer, it will be truncated and output. But frankly, 1024 chars should be enough in most cases (even less than this). Anyway, if this happens it will output a warning so you know about it.
Also note the vsnprintf() is not standard C (but it works in Android NDK). We could use vsprintf() instead (which is standard), but it is unsafe on its own.
======================================================================
Now for the dup() technique, you can look here (James Moore answer).
Then you can get rid of the function above and define your macro as:
#define LOG(...) fprintf(stderr, ...)
and you're done.
Advantages:
Disadvantages:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With