gpt4 book ai didi

c - 如何使用 JNI 打印宽字符

转载 作者:太空宇宙 更新时间:2023-11-03 23:48:44 25 4
gpt4 key购买 nike

32 位 Ubuntu 机器上,从 JDK 1.7.0 开始,我无法打印宽字符。

这是我的代码:

JNIFoo.java

public class JNIFoo {    
public native void nativeFoo();

static {
System.loadLibrary("foo");
}

public void print () {
nativeFoo();
System.out.println("The end");
}

public static void main(String[] args) {
(new JNIFoo()).print();
return;
}
}

foo.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include "JNIFoo.h"

JNIEXPORT void JNICALL Java_JNIFoo_nativeFoo (JNIEnv *env, jobject obj)
{
fwprintf(stdout, L"using fWprintf\n");
fflush(stdout);
}

然后我执行以下命令:

javac JNIFoo.java
javah -jni JNIFoo
gcc -shared -fpic -o libfoo.so -I/path/to/jdk/include -I/path/to/jdk/include/linux foo.c

这是根据用于执行程序的 JDK 的结果:

jdk1.6.0_45/bin/java -Djava.library.path=/path/to/jni_test JNIFoo

using fWprintf

The end

jdk1.7.0/bin/java -Djava.library.path=/path/to/jni_test JNIFoo

The end

jdk1.8.0_25/bin/java -Djava.library.path=/path/to/jni_test JNIFoo

The end

如您所见,对于 JDK 1.7 和 JDK 1.8,fwprintf 无效!

所以我的问题是我缺少什么才能使用 JDK 1.7(和 1.8)使用宽字符?

注意:如果我调用 fprintf 而不是 fwprintf,那么就没有问题,所有内容都会正确打印出来。

编辑

根据James的评论,我创建了一个main.c文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <wchar.h>
#include "JNIFoo.h"

int main(int argc, char* argv[])
{
fwprintf(stdout, L"In the main\n");
Java_JNIFoo_nativeFoo(NULL, NULL);

return 0;
}

然后我这样编译它:

gcc -Wall -L/path/to/jni_test -I/path/to/jdk1.8.0_25/include -I/pat/to/jdk1.8.0_25/include/linux main.c -o main -lfoo

并设置 LD_LIBRARY_PATH

export LD_LIBRARY_PATH=/path/to/jni_test

它工作正常:

In the main
using fWprintf

所以问题可能不是来自C。

注意:它在 64 位机器上工作正常。我在使用 linux Mint 32 位时遇到了类似的问题。

最佳答案

您不得将窄字符和宽字符混合打印到同一流中。 C99 引入了面向流的概念,据此 I/O 流可以面向宽面向字节(在 C99 之前,宽字符C 语言标准中不存在)。来自 C99 §7.19.2/4–5:

4) Each stream has an orientation. After a stream is associated with an external file, but before any operations are performed on it, the stream is without orientation. Once a wide character input/output function has been applied to a stream without orientation, the stream becomes a wide-oriented stream. Similarly, once a byte input/output function has been applied to a stream without orientation, the stream becomes a byte-oriented stream. Only a call to the freopen function or the fwide function can otherwise alter the orientation of a stream. (A successful call to freopen removes any orientation.)233)

5) Byte input/output functions shall not be applied to a wide-oriented stream and wide character input/output functions shall not be applied to a byte-oriented stream. [...]

233) The three predefined streams stdin, stdout, and stderr are unoriented at program startup.

C99 标准将混合窄字符和宽字符函数保留为未定义行为。实际上,GNU C 库表示“没有发出任何诊断。应用程序的行为只会很奇怪,或者应用程序只会崩溃。fwide 函数可以帮助避免这种情况。”(source)

由于 JRE 负责程序启动,它负责 stdinstdoutstderr 流,因此也负责它们方向。 Your JNI code is a guest in its house, don't go changing its carpets.实际上,这意味着您必须处理给定的任何流方向,您可以使用 fwide(3) 检测到它功能。如果您想将宽字符打印到面向字节的流,那就太糟糕了。您需要通过说服 JRE 使用面向宽的流,或将您的宽字符转换为 UTF-8 或其他方式来解决这个问题。

例如,这段代码应该适用于所有情况:

JNIEXPORT void JNICALL Java_JNIFoo_nativeFoo (JNIEnv *env, jobject obj)
{
if (fwide(stdout, 0) >= 0) {
// The stream is wide-oriented or unoriented, so it's safe to print wide
// characters
fwprintf(stdout, L"using fWprintf\n");
} else {
// The stream is narrow oriented. Convert to UTF-8 (and hopefully the
// terminal (or wherever stdout is going) can handle that)
char *utf8_string = convert_to_utf8(L"my wide string");
printf("%s", utf8_string);
}
fflush(stdout);
}

关于c - 如何使用 JNI 打印宽字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26422455/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com