API внешних функций и памяти Java, проблемы с локалью

Короче говоря, я вызывал нативные 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

на Java вы бы сделали Locale.setDefault(Locale.ROOT);

user85421 07.07.2024 13:04

нет, без изменений..

elect 07.07.2024 14:31

Минимальный воспроизводимый пример может улучшить ваш Вопрос.

Basil Bourque 07.07.2024 16:04

Что возвращает setlocale(LC_ALL, NULL)? Вы пробовали вызвать setlocale с Java?

Jorn Vernee 07.07.2024 18:08
atof() в коде C? Почему может возникнуть проблема с Java? Как упомянул @BasilBourque, необходим минимальный воспроизводимый пример.
aled 07.07.2024 18:13

@BasilBourque Добавлен минимальный воспроизводимый пример, это полный прототип, так что это непросто.

elect 07.07.2024 21:01

@aled да, на родном. Это проблема Java, потому что оригинальная версия Python Mala работает нормально, когда она вызывает собственные Lampps, это правильно анализирует число с плавающей запятой.

elect 07.07.2024 21:02

Я предлагаю попробовать воспроизвести, просто вызвав 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"‌​));

Jorn Vernee 07.07.2024 21:08

@JornVernee большое спасибо, Йорн, это на самом деле очень умно и намного эффективнее, извини, но я очень обгорел от этого..

elect 07.07.2024 21:30

Я могу воспроизвести, но установка export LC_ALL=C меня устраивает. Что произойдет, если вы распечатаете переменную с помощью System.getenv("LC_ALL") непосредственно перед вызовом atof? (Я предполагаю, что у вас установлена ​​локаль. т. е. она указана в locale -a)

Jorn Vernee 07.07.2024 22:00

за locale -a я обновил вопрос. Извините, но мне не ясно, как мне это применить export, если я запускаю все через Idea, я думаю, это может быть связано с Idea или Gradle... я прав?

elect 07.07.2024 22:14

Для Kotlin и Intellij IDEA в конфигурации запуска Kotlin должно быть поле Environment variables: , где вы можете его установить.

Jorn Vernee 07.07.2024 22:18

готово, здесь тоже решено.. уфф, большое спасибо, если вы хотите опубликовать это как правильный ответ, я буду более чем рад его принять

elect 07.07.2024 22:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
13
147
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я могу воспроизвести вашу проблему, если установлю локаль 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.*;

Другие вопросы по теме