Экранирование строки Java для кода JNI

У меня есть строковый литерал Java с символами Unicode, который необходимо преобразовать в строковый литерал C, который можно загрузить с помощью JNIEnv.NewString.

К сожалению, приведенный выше метод принимает указатель на массив unsigned short (jchar). Я пробовал использовать следующий код:

unsigned short str[] = {65, 66, 67};
jstring java_str = (*env)->NewString(env, str, 3);

Однако это занимает много места, неудобочитаемо для человека и сложно в обслуживании.

Есть ли способ преобразовать строковый литерал в unsigned short[] в C, сохраняя при этом возможность использовать символы Java UTF-16?

Можно ли это экранирование сделать программно? то есть преобразовать java.lang.String в строковый литерал, который будет работать в исходном коде C.


person konsolas    schedule 25.02.2017    source источник
comment
C имеет широкие строки, к сожалению, реализация определяет, какие наборы символов они используют, за исключением случаев, когда вы можете использовать C11.   -  person Antti Haapala    schedule 25.02.2017
comment
Строковый литерал C доступен только для чтения. Но пытаетесь ли вы сгенерировать исходный код C?   -  person Weather Vane    schedule 25.02.2017
comment
По сути, я бы предпочел не перерисовывать кучу строк вручную, поэтому было бы неплохо сгенерировать литералы. Если это невозможно, я могу избежать их вручную.   -  person konsolas    schedule 25.02.2017


Ответы (2)


Если вы можете использовать C11 и GCC, вы можете использовать новый char16_t, который будет UTF-16 в GCC:

#include <uchar.h>

#ifndef __STDC_UTF_16__
#error "char16_t not UTF-16"
#endif

...
    char16_t my_string[] = u"abc";
    jstring java_str = (*env)->NewString(env, str, 3);

И скомпилируйте с помощью gcc -std=c11

Но в любом случае, в большинстве случаев используются просто строки ASCII, и для этого можно просто использовать

jstring java_str = (*env)->NewStringUTF(env, "abc");

который будет предполагать, что строка находится в модифицированной кодировке UTF-8 (т. е. суррогатные пары UTF-16 кодируются отдельно в UTF-8 и заканчиваются нулем). Поскольку ASCII является подмножеством UTF-8, его можно использовать для строк ASCII.

person Antti Haapala    schedule 25.02.2017
comment
Это подходящее и целесообразное использование NewStringUTF, потому что строки являются литеральными строками в исходном коде, и может быть известно, что компилятору сообщается правильный исходный набор символов, а набор символов выполнения может быть выбран для совместимости с модифицированной UTF-8 для определенные диапазоны кодовых точек (включая U+0000 до D+D7FF). Рекомендуется комментировать исходный код на этот счет. Набор применимых наборов символов еще больше, если ваши данные ограничены элементами управления C0 и базовой латиницей (от U+0000 до U+007F). - person Tom Blodget; 26.02.2017
comment
Этот формат строкового литерала C11 кажется тем, что я искал. Спасибо! - person konsolas; 26.02.2017

То, что вы ищете, не называется побегом.

Похоже, что вы хотите указать строку символов в C, используя удобочитаемый строковый литерал, и иметь возможность передать ее в JNI NewString().

Вам придется прочитать wchar_t.

См. Что такое широкая строка символов в языке C? и https://en.wikibooks.org/wiki/C_Programming/C_Reference/wchar.h

Что вам нужно сделать, так это определить ваши строковые литералы как wchar_t (используя нотацию «L», описанную в предыдущих сообщениях), а затем написать функцию преобразования, которая преобразует эти массивы wchar_t в массивы jchar.

К сожалению, стандарт C не определяет точную реализацию wchar_t, а вместо этого предоставляет производителям компиляторов C делать то, что им заблагорассудится, поэтому есть вероятность, что ваш компилятор C не обрабатывает wchar_t как 16-битную величину. В этом случае ваша функция преобразования не сможет просто преобразовать массив wchar_t в массив jchar, и вместо этого ей придется преобразовывать их один за другим. Это немного хлопотно, но выполнимо. Удачи!

person Mike Nakis    schedule 25.02.2017