Reputation: 4603
I use a C library from Java through JNA and one function does not flush properly (since the output appear all at once on program end). I have tried Java side System.out.flush();
with no luck.
In brief, I would like to call C fflush(stdout)
from Java. With JNA already there (thus would prefer if no additional library) and without C to write.
I am aware of JNA Library mapping as in this question but that seems overkill to me.
Upvotes: 1
Views: 1904
Reputation: 4196
Adding this answer for Win32 / Win64 users, complementing FabienAndre's for GNU libc.
Selectively flushing the stdout stream calling the system's c library's fflush
method via jna is hard and cumbersome. As FabienAndre already mentioned, it is difficult to get a hold of the stdout
macro definition. For msvcrt (the Win32 / Win64 C library) it is defined via a function call to __iob_func()
; the latter returning a pointer to an array of FILE
structures. At index 0 is stdin, index 1 is stdout and index 2 is stderr. So for flushing stdout you even need to know the size of the FILE
structure, of course, it is different for Win32 and Win64 ...
The following example is tested under Win64 but ought to work under Win32. It was inspired by the thread JNA solutions to catch stdout/stderr of DLL.
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
public class JnaTest {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("msvcrt" , CLibrary.class);
Pointer __iob_func();
void printf(String format, Object... args);
int fflush (Pointer stream);
}
public static void main(String[] args) {
int sizeOfFileStructure = Platform.is64Bit() ? 48 : 32;
Pointer stdout = CLibrary.INSTANCE.__iob_func().share(sizeOfFileStructure);
CLibrary.INSTANCE.printf("Hello, World\n");
CLibrary.INSTANCE.fflush(stdout);
}
}
Upvotes: 1
Reputation: 4603
The JNA library wrapping way code is actually not so heavy (at least for the flush all behavior).
protected interface CLibrary extends Library
{
static CLibrary clib = (CLibrary) Native.loadLibrary ("c", CLibrary.class);
int fflush (Pointer stream);
}
/* ... */
CLibrary.clib.fflush (null);
JNA also offer late binding method and these oneliners will do what you want
NativeLibrary.getInstance ("c").getFunction ("fflush").invokeInt (new Object[]{0});
// even shorter
Function.getFunction ("c", "fflush").invokeInt (new Object[]{0});
The tedious part comes when you want to limit flushing to stdout
. You have to deal with vendor-specific code (stdout is either defined as a macro expanding to an array, Amtel avr-libc, to a function call, Microsoft msvcrt, or a pointer in GNU libc).
For the libc, you might use (two lines for legibility)
Pointer stdout = NativeLibrary.getInstance ("c").getGlobalVariableAddress ("stdout").getPointer (0);
Function.getFunction ("c", "fflush").invokeInt (new Object[]{stdout});
Upvotes: 2