Короче говоря, я вызывал нативные Lamps , используя новейший API внешних функций и памяти ( Project Panama ) в JDK 22.
У меня проблемы с локалью.
atof
будет анализировать 2.2598258677677969
как 2
, потому что в моей системе localeconv()->decimal_point
действительно есть ,
.
Я пытался установить на терминале export LC_ALL=C
и добавить сам собственный код.
#include <clocale>
setlocale(LC_ALL, "C");
Но пока никаких успехов у меня не было. К сожалению, я не знаком с родной средой.
Моя ОС — Linux (Ubuntu).
Чтобы воспроизвести:
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)
На родном это:
auto a = setlocale(LC_ALL, NULL);
utils::logmesg(this, "old locale {}\n", a);
печатает следующее
старая локаль 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 -a
С C.utf8 ПОСИКС de_AT.utf8 de_BE.utf8 de_CH.utf8 de_DE.utf8 de_IT.utf8 de_LI.utf8 de_LU.utf8 ru_AG ru_AG.utf8 ru_AU.utf8 ru_BW.utf8 ru_CA.utf8 ru_DK.utf8 ru_GB.utf8 ru_HK.utf8 ru_IE.utf8 ru_IL ru_IL.utf8 ru_IN ru_IN.utf8 ru_NG ru_NG.utf8 ru_NZ.utf8 ru_PH.utf8 ru_SG.utf8 ru_US.utf8 ru_ZA.utf8 ru_ZM ru_ZM.utf8 ru_ZW.utf8 it_CH.utf8 it_IT.utf8
нет, без изменений..
Минимальный воспроизводимый пример может улучшить ваш Вопрос.
Что возвращает setlocale(LC_ALL, NULL)
? Вы пробовали вызвать setlocale
с Java?
atof()
в коде C? Почему может возникнуть проблема с Java? Как упомянул @BasilBourque, необходим минимальный воспроизводимый пример.
@BasilBourque Добавлен минимальный воспроизводимый пример, это полный прототип, так что это непросто.
@aled да, на родном. Это проблема Java, потому что оригинальная версия Python Mala работает нормально, когда она вызывает собственные Lampps, это правильно анализирует число с плавающей запятой.
Я предлагаю попробовать воспроизвести, просто вызвав atof
напрямую, это не потребует от людей клонирования и создания множества репозиториев. например Linker l = Linker.nativeLinker(); var atof = l.downcallHandle(l.defaultLookup().find("atof").get(), FunctionDescriptor.of(ValueLayout.JAVA_DOUBLE, ValueLayout.ADDRESS)); double res = (double) atof.invoke(Arena.global().allocateFrom("2.2598258677677969"));
@JornVernee большое спасибо, Йорн, это на самом деле очень умно и намного эффективнее, извини, но я очень обгорел от этого..
Я могу воспроизвести, но установка export LC_ALL=C
меня устраивает. Что произойдет, если вы распечатаете переменную с помощью System.getenv("LC_ALL")
непосредственно перед вызовом atof
? (Я предполагаю, что у вас установлена локаль. т. е. она указана в locale -a
)
за locale -a
я обновил вопрос. Извините, но мне не ясно, как мне это применить export
, если я запускаю все через Idea, я думаю, это может быть связано с Idea или Gradle... я прав?
Для Kotlin и Intellij IDEA в конфигурации запуска Kotlin должно быть поле Environment variables:
, где вы можете его установить.
готово, здесь тоже решено.. уфф, большое спасибо, если вы хотите опубликовать это как правильный ответ, я буду более чем рад его принять
Я могу воспроизвести вашу проблему, если установлю локаль LC_NUMERIC
на it_IT.utf8
:
setlocale(LC_NUMERIC(), Arena.global().allocateFrom("it_IT.utf8"));
var res = atof(Arena.global().allocateFrom("2.2598258677677969"));
System.out.println(res); // 2.0
Как вы обнаружили, установка переменной среды LC_ALL
значения C
должна решить проблему и заставить atof
вернуть 2.259825867767797
. Вы можете убедиться, что LC_ALL
установлен правильно, распечатав результат System.getenv("LC_ALL")
непосредственно перед вызовом atof
.
В качестве альтернативы вы можете явно установить LC_ALL
(или просто LC_NUMERIC
) в C
в начале вашей программы, вызвав setlocale
:
setlocale(LC_ALL(), Arena.global().allocateFrom("C"));
Обратите внимание, что LC_ALL
и LC_NUMERIC
определяются реализацией, поэтому для приведенных выше фрагментов я использую jextract-интерфейс стандартной библиотеки C, который даст мне правильные значения LC_ALL
и LC_NUMERIC
. Образец смотрите здесь.
Чтобы сгенерировать интерфейс, установите jextract и Java 22, добавьте каталог bin
обоих в свой PATH
, а затем выполните следующие 2 команды:
$ jextract --output src -t libc --header-class-name LibC 'libc.h'
$ javac -d classes src/**/*.java
Файл libc.h
содержит только #include
всех заголовочных файлов стандартной библиотеки C , минус stdbit.h
и stdckdint.h
, которые на момент написания слишком новые.
Это должно создать каталог src
с извлеченными исходными кодами и выдать все скомпилированные классы в каталог classes
, который затем можно будет добавить в путь к классам вашего JVM-приложения. Сгенерированные классы и функции можно импортировать с помощью:
import static libc.LibC.*;
import libc.*;
на Java вы бы сделали
Locale.setDefault(Locale.ROOT);