Reputation: 16385
I my cpp code contains a jni function that i wish to convert to const char*. This is the code i am using
extern "C" {
void Java_com_sek_test_JNITest_printSomething(JNIEnv * env, jclass cl, jstring str) {
const char* mystring = env->GetStringUTFChars(env, str, 0);
PingoScreen::notify();
}
I get an error that
no matching function for call to '_JNIEnv::GetStringUTFChars(JNIEnv*&, _jstring*&, int)
What am i doing wrong ?
Upvotes: 1
Views: 11648
Reputation: 20782
There several things that aren't quite right with your code and approach:
(env*)->JNIFunc(env,...)
should be env->JNIFunc(...)
in C++. Your vendor's (Google Android's) jni.h simplifies the C++ syntax over the C syntax.GetStringUTFChars
. It's a pointer for an output parameter. The result isn't very interesting so pass nullptr
. GetStringUTFChars
et al). There should be no need to ever use that encoding. Java classes are very capable at converting encodings. They also give you control over what happens when a character cannot be encoded in the target encoding. (The default is to convert it to a ?
.)jstring
) to a pointer to one byte storage (char*
) needs a lot of refinement. You probably want to copy the characters in a JVM java.lang.String
to a "native" string using a specific or OS-default encoding. The Java string has Unicode characters with a UTF-16 encoding. Android generally uses the Unicode character set with the UTF-8 encoding. If do you need something else, you can specify it with a Charset
object.std::string
to hold counted byte-sequences for a string. You can get a pointer to a null-terminated buffer from a std::string
if you need it.Be sure to read Android's JNI Tips.
Here is an implementation of your function that lets the vendor's JVM implementation pick the target encoding (which is UTF-8 for Android):
extern "C" JNIEXPORT void Java_com_sek_test_JNITest_printSomething
(JNIEnv * env, jclass cl, jstring str) {
// TODO check for JVM exceptions where appropriate
// javap -s -public java.lang.String | egrep -A 2 "getBytes"
const auto stringClass = env->FindClass("java/lang/String");
const auto getBytes = env->GetMethodID(stringClass, "getBytes", "()[B");
const auto stringJbytes = (jbyteArray) env->CallObjectMethod(str, getBytes);
const auto length = env->GetArrayLength(stringJbytes);
const auto pBytes = env->GetByteArrayElements(stringJbytes, nullptr);
std::string s((char *)pBytes, length);
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
const auto pChars = s.c_str(); // if you really do need a pointer
}
However, I'd probably do the call to String.getBytes
on the Java side, defining the native method to take a byte array instead of a string.
(Of course, implementations that use GetStringUTFChars do work for some subset of Unicode strings but why impose an esoteric and needless limit?)
Upvotes: 4
Reputation: 1161
According to the documentation,
GetStringUTFChars const jbyte* GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
Returns a pointer to an array of bytes representing the string in modified UTF-8 encoding. This array is valid until it is released by ReleaseStringUTFChars().
If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; or it is set to JNI_FALSE if no copy is made.
So the last parameter should be a jboolean;
Upvotes: 2
Reputation: 2664
Try... Change this line
const char* mystring = env->GetStringUTFChars(env, str, 0);
to
const char *mystring = (*env)->GetStringUTFChars(env, str, 0);
Hope it works:)
Upvotes: 1