JDK22 Foreign Function & Memory API调用Lammps的Locale问题
在Ubuntu系统上使用JDK 22的Foreign Function & Memory API(Project Panama)调用原生Lammps程序时,遇到Locale导致的数值解析错误:系统localeconv()->decimal_point为逗号,使得atof函数将字符串2.2598258677677969解析为2。尝试过终端执行export LC_ALL=C、在原生代码中添加#include <clocale>和setlocale(LC_ALL, "C"),均未解决问题。
复现信息
Kotlin调用代码
val l = Linker.nativeLinker() val d = FunctionDescriptor.of(ValueLayout.JAVA_DOUBLE, ValueLayout.ADDRESS) val atof = l.downcallHandle(l.defaultLookup().find("atof").get(), d) val res = atof.invoke(Arena.global().allocateFrom("2.2598258677677969")) as Double println(res)
原生代码Locale检查
auto a = setlocale(LC_ALL, NULL); utils::logmesg(this, "old locale {}\n", a);
输出的Locale信息
old locale LC_CTYPE=en_US.UTF-8;LC_NUMERIC=it_IT.UTF-8;LC_TIME=it_IT.UTF-8;LC_COLLATE=en_US.UTF-8;LC_MONETARY=it_IT.UTF-8;LC_MESSAGES=en_US.UTF-8;LC_PAPER=it_IT.UTF-8;LC_NAME=it_IT.UTF-8;LC_ADDRESS=it_IT.UTF-8;LC_TELEPHONE=it_IT.UTF-8;LC_MEASUREMENT=it_IT.UTF-8;LC_IDENTIFICATION=it_IT.UTF-8
系统可用Locale
执行locale -a可见C、C.utf8、POSIX等Locale。
解决方案
1. 单独设置LC_NUMERIC而非LC_ALL
从输出可见LC_NUMERIC仍为it_IT.UTF-8,说明之前的LC_ALL设置未覆盖到该字段。尝试在原生代码中单独设置数值相关Locale,且确保在任何数值解析逻辑之前调用:
#include <clocale> // 初始化阶段调用 setlocale(LC_NUMERIC, "C"); // 验证设置结果 const char* numLocale = setlocale(LC_NUMERIC, NULL); printf("Current LC_NUMERIC: %s\n", numLocale);
2. 启动Java程序时强制设置环境变量
如果原生代码设置不生效,可在启动Java程序时直接指定LC_NUMERIC或LC_ALL:
LC_NUMERIC=C java -jar your-application.jar # 或 LC_ALL=C java -jar your-application.jar
3. 检查Lammps内部Locale逻辑
部分大型原生程序(如Lammps)可能会在内部重置Locale设置,需确认Lammps代码中是否有覆盖Locale的逻辑,如有需调整其执行顺序或关闭该逻辑。
4. 验证字符串编码传递
确保Panama传递的字符串编码符合原生函数预期,可明确指定ASCII编码:
val strArena = Arena.global().allocateFrom("2.2598258677677969", Charsets.US_ASCII) val res = atof.invoke(strArena) as Double
内容的提问来源于stack exchange,提问作者elect

