Wednesday, January 16, 2008

Functions with a Variable Argument List

My current project is a JNI application - invokes C++ code from Java. I began implementation of a Logger component for the C++ part. As usually I wanted to integrate it very easy with just replacing the previous printing to stdout (printf) with a utility method (log) eg:
replace: printf("Error = %d (%s)", error, errorMessage);
with : log("Error = %d (%s)", error, errorMessage);
The signature of the log method is: log(const char * message, ...) that should print the log message to a file with: fprintf (file, messageString).

The big problem turned out to be - how to pass all the arguments from log to fprintf - both methods with variable argument list ...

Some ideas:
  1. All the tutorials learn you how to iterate those variable arguments and manipulate them separately - time consuming
  2. Overloade operator << - a lot of refactoring required.
  3. A cool idea was to redirect the System.out from Java to a file with System.setOut(printStream) - stdout is not the same as System.out
A possible sollution is to redirect the stdout from the C++ code to a file and skip the whole Logger component - the printf will append to the log file:
std::freopen(LOG_FILE, "a", stdout);
The big side effect is that the Java System.out stream is also redirected and writes to the file.

And the winner is:

#include "stdio.h"
#include "stdarg.h"
log(const char * message, ...) {
char buffer[512]
va_list args;
va_start(args, message);
// Returns the size of the created message
vsnprintf(buffer, sizeof(buffer), message, args);
fprintf (file, buffer);

vsnprintf formats the message with the argument list and writes it to the buffer that is easily logged.

Clean sollution but far from my Java-stuffed brain.

A solution for exception handling in JNI is in: Functions with a Variable Argument List II
You can also take a look at this post for more tips&trick for JNI.

1 comment:

Adam said...

Thanks, this was useful.