Calling C + + from Java
When the entire application cannot be written in the Java language, JNI allows you to invoke C + + native code. In the following typical scenarios, you may decide to use native code:
You want to use a lower-level, faster programming language C + + to implement code that is demanding time.
You want to access the old code or code base from a Java program.
Platform-dependent features that are not supported in the standard Java class library are required.
I need it for the code background
In my Android project, I need to use the C + + SoundTouch library function.
Five steps to call C/A + + from Java code
The process of calling C or C + + code from a Java program consists of six steps. We'll go into each step in depth, and we'll start by looking at them quickly.
Write Java code . We'll start with writing Java classes that perform three tasks: declaring a native method that will be called, loading a shared library containing native code, and then calling the native method.
Create a C + + header file . The C + + header file declares the description of the native function that you want to invoke. This header file then creates a shared library (see step 5), together with the C + + function implementation (see step 4).
Write C + + code . This step implements the functions in the C or C + + source code files. The C + + source file must contain the header file that you created in step 3.
Create a shared library file . Create a shared library file from the C source code file that you created in step 4.
Run Java program . Run the code and see if it is useful. We will also discuss some of the techniques used to solve common mistakes.
Code directory structure (for example, my Code structure)
src(put Java code)
|_ Org.tecunhuman. JNI Package (custom named Package)
|_ Wrapperjni.java (Java code written by yourself)
JNI (put C + + code)
|_ Soundstrech Package (my C + + code)
|_ Gen
|_ android.mk
|_ RunParameters.cpp
|_ RunParameters.h
|_ SoundStrech.cpp
|_ SoundStrech.h
|_ WavFile.cpp
|_ WavFile.h
|_ wrapper.i
|_ SoundTouch Library
——————————————————————————————
Steps
1
: Write
Java
Code
We start by writing a Java source code file that declares a native method (or method), loads a shared library containing native code, and then actually calls the native method.
Package Org.tecunhuman.jni;class Wrapperjni {//Declares native method, cannot implement it (like abstract method, but uses different) public final static native long New_soun DStretch (); Public final static native void Delete_soundstretch (long jarg1); Public final static native void Soundstretch_process (long jarg1, Soundstretch jarg1_, String jarg2, String jarg3, float ja RG4, float jarg5, float jarg6);}
What does this piece of code do?
First, note the use of the native keyword, which can only be used with methods. The native keyword tells the Java compiler that the method is implemented with native code outside of the Java class, but its declaration is in Java. Native methods can only be declared in a Java class, not by implementing it (but not as an abstract method, using the native keyword), so the native method cannot have a method body .
Steps
2
: Generated by the Javah command
C + +
header File
C + + header file that defines the native function description. One way to do this is to use Javah.exe, which is a native method C stub generator tool that comes with the SDK. This tool is designed to create a header file that defines a C-style function for each native method found in the Java source code file. The commands used here are:
CD test/. Javah–classpath. Test. Sample1
In SoundStrech.h, for example, the code looks like this:
#ifndef soundstretch_h#define Soundstretch_h#include <string> class Soundstretch {public:soundstretch (); ~soundstretch (); void process (std::string infilename, std::string outfilename, float Tempodelta, Float Pitchdelta, float ratedelta);}; #endif
about the C + + header File
As you may have noticed, there is a big difference between the C/C + + function descriptions in Sample1.h and the Java native method declarations in Sample1.java. Jniexport and Jnicall are compiler-dependent indicators for exporting functions. The return type is a C + + type that is mapped to a Java type. These types are fully described in the appendix A:jni types.
In addition to the general parameters in the Java declaration, all of these functions have a pointer to jnienv and jobject in the parameter table. A pointer to jnienv is actually a pointer to a table of function pointers. As you will see in step 4, these functions provide a variety of capabilities to manipulate Java data in C and C + +.
The Jobject parameter references the current object. Therefore, if C or C + + code needs to reference a Java function, the Jobject acts as a reference or pointer, returning the calling Java object. The function name itself is composed of the prefix "Java_" plus the fully qualified class name, plus the underscore and the method name.
JNI type
JNI uses several native-defined C types that map to Java types. These types can be divided into two categories: primitive types and pseudo-classes (pseudo-classes). In C, pseudo-classes are implemented as structs, whereas in C + + they are real classes.
The Java primitive type maps directly to the platform-dependent type of C, as follows:
The C-type Jarray represents a universal array. In C, all array types are actually just jobject synonymous types. However, in C + +, all array types inherit Jarray,jarray and inherit jobject in succession. The following table shows how the Java array type is mapped to the JNI C array type.
Here is a tree of objects that shows how the JNI pseudo-class is related.
Steps
3
: Write
C + +
Code
One thing to keep in mind when it comes to writing a C + + function implementation is that the description must be exactly the same as the Sample1.h function declaration. We'll look at the complete code for C implementations and C + + implementations, and then discuss the differences between the two.
C Function implementation
Here is sample1.c, which is an implementation written in C:
#include "Test_sample1.h"
#include <string.h>
Jniexport Jint Jnicalljava_test_sample1_intmethod
(jnienv *env, jobject obj, Jint num) {
return num * num;
}
Jniexport Jboolean Jnicalljava_test_sample1_booleanmethod
(jnienv *env, Jobject obj, Jboolean boolean) {
Return!boolean;
}
Jniexport jstring Jnicalljava_test_sample1_stringmethod
(jnienv *env, Jobject obj, jstring string) {
const char *STR = (*env)->getstringutfchars (env, string, 0);
CHARCAP[128];
strcpy (Cap, str);
(*env)->releasestringutfchars (env, string, str);
Return (*ENV)->newstringutf (env, STRUPR (CAP));
}
Jniexport Jint Jnicall Java_test_sample1_intarraymethod
(jnienv *env, jobject obj, Jintarray array) {
Inti, sum = 0;
Jsize len = (*env)->getarraylength (env, array);
Jint*body = (*env)->getintarrayelements (env, array, 0);
for (i=0; i<len; i++)
{sum + = Body[i];
}
(*env)->releaseintarrayelements (env, array, body, 0);
return sum;
}
void Main () {}
C + + function implementation
The following is the Sample1.cpp (c + + implementation)
#include "Test_sample1.h"
#include <string.h>
Jniexport Jint Jnicall Java_sample1_intmethod
(jnienv*env, Jobject obj, Jint num) {
return num* num;
}
Jniexport Jboolean Jnicalljava_sample1_booleanmethod
(jnienv *env,jobject obj, Jboolean boolean) {
Return!boolean;
}
Jniexport jstring Jnicall Java_sample1_stringmethod
(jnienv*env, Jobject obj, jstring string) {
Constchar *str = env->getstringutfchars (string, 0);
CHARCAP[128];
strcpy (Cap, str);
Env->releasestringutfchars (string, str);
Returnenv->newstringutf (STRUPR (CAP));
}
Jniexport Jint Jnicall Java_sample1_intarraymethod
(jnienv*env, Jobject obj, Jintarray array) {
int i,sum = 0;
Jsizelen = env->getarraylength (array);
Jint*body = env->getintarrayelements (array, 0);
for (i=0; i<len; i++)
{sum + = Body[i];
}
Env->releaseintarrayelements (array, body, 0);
Returnsum;
}
void Main () {}
Comparison of C and C + + function implementations
The only difference is the method used to access the JNI function. In C, the JNI function call is prefixed by "(*env)," to remove the value referenced by the function pointer. In C + +, the JNIEnv class has an inline member function that handles the lookup of a function pointer. This subtle difference is illustrated below, where the two lines of code access the same function, but each language has its own syntax.
C syntax:jsize len = (*env)->getarraylength (Env,array);
C + + syntax:jsize len =env->getarraylength (array);
Steps
4
: Create a shared library file
Next, we create a shared library file that contains native code. Most C and C + + compilers can create shared library files in addition to the machine code executable files. The command used to create a shared library file depends on the compiler you are using. Here are the commands that are executed on Windows and Linux systems.
Windows : using the Visual Studio Commandprompt tool Cl.exe
Cl-i "C:\Program files\java\jdk1.6.0_23\include"-i "C:\Program files\java\jdk1.6.0_23\include\win32"-ld Sample1.c-fesample1.dll
Linux : using the GCC tool
Gcc-c-fpic-i/usr/java/jdk1.6.0_22/include/-i/usr/java/jdk1.6.0_22/include/linux/sample1.c
Gcc-shared-fpic-o libsample1.so SAMPLE1.O
Steps
5
: Run
Java
program
The final step is to run the Java program and make sure the code works correctly. Because all Java code must be executed in a Java virtual machine, you need to use the Java Runtime environment. One way to do this is to use Java, which is the Java interpreter provided with the SDK. The commands that are used are:
JAVA-CP. Test. Sample1
Output:
Intmethod:25
Booleanmethod:false
Stringmethod:java
Intarraymethod:33
Troubleshooting
When you use JNI to access native code from a Java program, you encounter many problems. The three most common errors you will encounter are:
cannot find dynamic link . The error message that it generates is: Java.lang.UnsatisfiedLinkError. This usually means that the shared library cannot be found, or that a specific native method within the shared library cannot be found.
The shared library file could not be found . When loading an inbound file with the System.loadlibrary (String libname) method (the parameter is the file name), make sure that the file name is spelled correctly and that no extension is specified. Also, make sure that the location of the library file is in the classpath so that the JVM can access the library file.
Unable to find a method with the specified description . Make sure that your C + + function implementation has the same description as the function description in the header file.
Reference documents:
Http://www.cnblogs.com/BloodAndBone/archive/2010/12/22/1913882.html
Http://www.360doc.com/content/13/0530/14/110467_289211699.shtml
"JNI Programming"--calling C + + from Java