在Java中使用调用c++程序时,遇到了标准输出输出顺序的一个问题。
假设有Java代码如下
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
System.loadLibrary("JNITest");
HelloCpp a = new HelloCpp();
a.hellocpp();
}
}
public class HelloCpp {
public native void hellocpp();
}
C++代码如下
JNIEXPORT void JNICALL Java_HelloCpp_hellocpp(JNIEnv *, jobject)
{
printf("hello from cpp\n");
}
上述代码成功编译执行后的控制台输出为
Hello World!
Hello Java!
hello from cpp
这样的内容,显然不是我们所预期的。具体来说就是即使C++的输出在执行的时候在Java之前,Java的也会先输出,C++的会后输出。百度之后找到了这样一个帖子
https://bbs.csdn.net/topics/391939316
有人回答是
如我们上面谈到的,这里涉及到跨进程通信,这个过程是耗时的,所以可能存在消息延迟。
就结论而言,该说法是错的。在得到结论之前我们来更换一下代码试试。C++的改成如下代码:
JNIEXPORT void JNICALL Java_HelloCpp_hellocpp(JNIEnv *, jobject)
{
cout << "hello from cpp" << endl;
}
我们会得到输出
Hello World!
hello from cpp
Hello Java!
看吧,如果如帖子中的回答那样,这里不应该出现这样的结果的。几乎所有C++的书上都会写std::endl和"\n"的区别,那就是刷新缓冲区。因此使用如下代码是可以得到同样的结果的
JNIEXPORT void JNICALL Java_HelloCpp_hellocpp(JNIEnv *, jobject)
{
printf("hello from cpp\n");
cout.flush();
}
这就说明了,JNI的C++程序的标准输出拥有自己独立的缓冲区,Java代码拥有自己的缓冲区,它们互不影响,每次刷新缓冲区,C++才能将标准输出送到Java的控制台,二者输出顺序与进程通信什么的没有丝毫关系,仅仅是因为缓冲区的问题。