GetStringChars should be simple

Q

Québec

Hi,
Should be simple after all. I tried this with the help of CoreJava2 vol2.

serie.o(.text+0x25):serie.c: undefined reference to `GetStringChars'
serie.o(.text+0x4e):serie.c: undefined reference to `GetStringLength'
serie.o(.text+0xc4):serie.c: undefined reference to `NewStringUTF'


==========
//serial.c

#include "Serial.h"
#include <stdio.h>

JNIEXPORT jstring JNICALL Java_Serial_numero
(JNIEnv *env, jobject jobjc, jstring jstr){
jboolean *iscopy;
jstring ret;
jsize len;
const char* fmt;
fmt = (*env)-->GetStringChars(env, jstr, iscopy);
len = (*env)-->GetStringLength(env, jstr);

printf("%d", len);
printf("%s", fmt);
printf("%s", ret);
fflush(stdout);

ret = (*env)-->NewStringUTF(env, fmt);

return ret;
}


---------------
public class Serial
{

public static void main(String[] args)
{
Serial serie = new Serial();

System.out.println(serie.numero("Jean"));
}

public native int numero(String one);

static
{
System.loadLibrary("serial");
}
}
-------------
 
G

Gordon Beaton

Should be simple after all. I tried this with the help of CoreJava2 vol2.

serie.o(.text+0x25):serie.c: undefined reference to `GetStringChars'
serie.o(.text+0x4e):serie.c: undefined reference to `GetStringLength'
serie.o(.text+0xc4):serie.c: undefined reference to `NewStringUTF'
[...]

fmt = (*env)-->GetStringChars(env, jstr, iscopy);
len = (*env)-->GetStringLength(env, jstr);

Post your real code if that isn't it (don't retype it when you post).

If that *is* your real code, then you should probably brush up on some
basic C before trying your hand at JNI. Write it like this instead:

fmt = (*env)->GetStringChars(env, jstr, iscopy);
len = (*env)->GetStringLength(env, jstr);

Count those hyphens.

/gordon
 
Q

Québec

I am lost

serie.c:13: warning: comparison between pointer and integer
serie.c:13: warning: assignment makes pointer from integer without a cast
serie.c:14: warning: comparison between pointer and integer
serie.c:14: warning: assignment makes pointer from integer without a cast
serie.c:21: warning: comparison between pointer and integer
serie.c:21: warning: assignment makes pointer from integer without a cast


==== improved code ! ====
//serial.c


#include "Serial.h"
#include <stdio.h>

JNIEXPORT jstring JNICALL Java_Serial_numero (JNIEnv *env, jobject jobjc,
jstring jstr){
jboolean *iscopy;
jstring ret;
jint len;
const char* fmt;
fmt = (*env)-->GetStringChars(env, jstr, iscopy);
len = (*env)-->GetStringLength(env, jstr);

printf("%d", len);
printf("%s", fmt);
printf("%s", ret);
fflush(stdout);

ret = (*env)-->NewStringUTF(env, fmt);
return ret;
}
 
E

Eric Sosman

Québec said:
I am lost

serie.c:13: warning: comparison between pointer and integer
serie.c:13: warning: assignment makes pointer from integer without a cast
serie.c:14: warning: comparison between pointer and integer
serie.c:14: warning: assignment makes pointer from integer without a cast
serie.c:21: warning: comparison between pointer and integer
serie.c:21: warning: assignment makes pointer from integer without a cast


==== improved code ! ====
//serial.c


#include "Serial.h"
#include <stdio.h>

JNIEXPORT jstring JNICALL Java_Serial_numero (JNIEnv *env, jobject jobjc,
jstring jstr){
jboolean *iscopy;
jstring ret;
jint len;
const char* fmt;
fmt = (*env)-->GetStringChars(env, jstr, iscopy);

C's pointer indirection operator is spelled `->', not
`-->'. As it stands, you've written

fmt = (*env)-- > GetStringChars(...)

There may be other problems, too -- I've never written any
JNI code, and am not familiar with its conventions.
 
Q

Québec

I just read your first post. I do really feel dum.

The dll is created.

--------
Exception in thread "main" java.lang.UnsatisfiedLinkError: numero
at Serial.numero(Native Method)
at Serial.main(Serial.java:6)

------------
#include "Serial.h"
#include <stdlib.h>

JNIEXPORT jstring JNICALL Java_Serial_numero (JNIEnv *env, jobject jobjc,
jstring jstr){
jboolean *iscopy;
jstring ret;
jint len;
const jchar *fmt;
fmt = (*env)->GetStringChars(env, jstr, iscopy);
len = (*env)->GetStringLength(env, jstr);
ret = (*env)->NewString(env, fmt,len);
return ret;
}
==============
public class Serial
{ public static void main(String[] args)
{
Serial serie = new Serial();
System.out.println(serie.numero("Jean"));
}

public native String numero(String one);

static
{
System.loadLibrary("serial");
}
}
==========
Jean
 
Q

Québec

I just read your first post. I do really feel dum.

The dll is created.

--------
Exception in thread "main" java.lang.UnsatisfiedLinkError: numero
at Serial.numero(Native Method)
at Serial.main(Serial.java:6)

------------
#include "Serial.h"
#include <stdlib.h>

JNIEXPORT jstring JNICALL Java_Serial_numero (JNIEnv *env, jobject jobjc,
jstring jstr){
jboolean *iscopy;
jstring ret;
jint len;
const jchar *fmt;
fmt = (*env)->GetStringChars(env, jstr, iscopy);
len = (*env)->GetStringLength(env, jstr);
ret = (*env)->NewString(env, fmt,len);
return ret;
}
==============
public class Serial
{ public static void main(String[] args)
{
Serial serie = new Serial();
System.out.println(serie.numero("Jean"));
}

public native String numero(String one);

static
{
System.loadLibrary("serial");
}
}
==========
Jean
 
Q

Québec

I just read your first post. I do really feel dum.

The dll is created.

--------
Exception in thread "main" java.lang.UnsatisfiedLinkError: numero
at Serial.numero(Native Method)
at Serial.main(Serial.java:6)

------------
#include "Serial.h"
#include <stdlib.h>

JNIEXPORT jstring JNICALL Java_Serial_numero (JNIEnv *env, jobject jobjc,
jstring jstr){
jboolean *iscopy;
jstring ret;
jint len;
const jchar *fmt;
fmt = (*env)->GetStringChars(env, jstr, iscopy);
len = (*env)->GetStringLength(env, jstr);
ret = (*env)->NewString(env, fmt,len);
return ret;
}
==============
public class Serial
{ public static void main(String[] args)
{
Serial serie = new Serial();
System.out.println(serie.numero("Jean"));
}

public native String numero(String one);

static
{
System.loadLibrary("serial");
}
}
==========
Jean
 
G

Gordon Beaton

The dll is created.

UnsatisfiedLinkError can be caused by essentially two things: the DLL
could not be loaded (System.loadLibrary() fails) or the native method
was not found in the DLL (either because it is missing or has the
wrong name).

You have another serious problem as well:
jboolean *iscopy;
fmt = (*env)->GetStringChars(env, jstr, iscopy);

These lines should look like this instead:

jboolean iscopy;
fmt = (*env)->GetStringChars(env, jstr, &iscopy);

It is never meaningful to pass an uninitialized pointer to a function
in C, and doing so will likely cause your program to crash or
otherwise fail in mysterious ways.

/gordon
 
Q

Québec

Everything of the first c file works perfectly. The string ret is returned
and printed has are the printf lines.

The following modified code runs fine. The string ret is returned and
printed has are the printf lines.

Except what is in between the dashed lines does not printf. Once again it
is one of theese pointers misunderstanding. I tried it apart ( what is in
between the dashed lines) in many ways has a regular C.exe.
========================
/*serial.c
#include "Serial.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char lettres[] = {
'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J', 'K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n', ' ',
'o','p','q','r','s','t','u','v','w','x','y','z', '_', '-'};

JNIEXPORT jstring JNICALL Java_Serial_numero
(JNIEnv *env, jobject jobjc, jstring jstr){
jboolean iscopy;
jstring ret;
jint len;

int i, j;
char lettres[65];
const char *fmt = NULL;
char ligne[len]; // no complain
about this line but...

fmt = (*env)->GetStringUTFChars(env, jstr, &iscopy);
len = (*env)->GetStringLength(env, jstr);

printf("The string received by C: %s has %d characters.\n", len, fmt);
----------------------------------------------------------------------------
------------------
for(i=0;i<len;i++){
for(j=0;j<66;j++){
if( lettres[j] == ligne){
ligne = lettres[65-j];
printf(": %c\n", ligne);
break;
}
}
}
printf("The mixed string by C: %s\n", ligne);
----------------------------------------------------------------------------
--------------------------------------
ret = (*env)->NewStringUTF(env, fmt);
return ret;
}

Many thanks.

Jean
 
G

Gordon Beaton

Except what is in between the dashed lines does not printf. Once again it
is one of theese pointers misunderstanding. I tried it apart ( what is in
between the dashed lines) in many ways has a regular C.exe.
[...]

char lettres[] = {
'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J', 'K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n', ' ',
'o','p','q','r','s','t','u','v','w','x','y','z', '_', '-'};

JNIEXPORT jstring JNICALL Java_Serial_numero
(JNIEnv *env, jobject jobjc, jstring jstr){
jboolean iscopy;
jstring ret;
jint len;

int i, j;
char lettres[65];
const char *fmt = NULL;
char ligne[len]; // no complain
about this line but...

fmt = (*env)->GetStringUTFChars(env, jstr, &iscopy);
len = (*env)->GetStringLength(env, jstr);

printf("The string received by C: %s has %d characters.\n", len, fmt);
----------------------------------------------------------------------------
------------------
for(i=0;i<len;i++){
for(j=0;j<66;j++){
if( lettres[j] == ligne){
ligne = lettres[65-j];
printf(": %c\n", ligne);
break;
}
}
}
printf("The mixed string by C: %s\n", ligne);


You have declared two different arrays "lettres". You don't initialize
the second one, which also happens to be the one seen inside the
native method.

You have declared an array "ligne" of some *random* length (but
probably zero) because "len" has not yet been assigned a value at the
point where you use it to create "ligne". Later, you assign a value to
"len" but this has no bearing on the already created array "ligne".

In the loop, you refer to the contents of both "lettres" and "ligne",
neither of which have been intialized. Also, you likely access beyond
the end of "ligne" because of the issue with "len".

None of this has anything to do with JNI. If you have questions about
basic C programming issues, please take them to comp.lang.c or
comp.lang.c.moderated.

/gordon
 
Q

Québec

Everything of the first c file works perfectly. The string ret is returned
and printed has are the printf lines.

The following modified code runs fine. The string ret is returned and
printed has are the printf lines.

Except what is in between the dashed lines does not printf. Once again it
is one of theese pointers misunderstanding. I tried it apart ( what is in
between the dashed lines) in many ways has a regular C.exe.
========================
/*serial.c
#include "Serial.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char lettres[] = {
'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J', 'K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n', ' ',
'o','p','q','r','s','t','u','v','w','x','y','z', '_', '-'};

JNIEXPORT jstring JNICALL Java_Serial_numero
(JNIEnv *env, jobject jobjc, jstring jstr){
jboolean iscopy;
jstring ret;
jint len;

int i, j;
char lettres[65];
const char *fmt = NULL;
char ligne[len];

/*
DEVC++
I did not succeed creating a working dll with DEV C++
dllwrap.exe --output-def libserial.def --implib libserial.a serie.o
serial_private.res -L"C:/Dev-Cpp/lib" -L"F:/unzipM_soft/w32api-2.0/lib" -L"C
:/jdk1.1.8/lib" -L"C:/jdk1.1.8/bin" -o serial.dll

dllwrap.exe: no export definition file provided.
Creating one, but that may not be what you want


but the borland linker char ligne[len]; <==Constant expression required
*/

fmt = (*env)->GetStringUTFChars(env, jstr, &iscopy);
len = (*env)->GetStringLength(env, jstr);

printf("The string received by C: %s has %d characters.\n", len, fmt);
----------------------------------------------------------------------------
------------------
for(i=0;i<len;i++){
for(j=0;j<66;j++){
if( lettres[j] == ligne){
ligne = lettres[65-j];
printf(": %c\n", ligne);
break;
}
}
}
printf("The mixed string by C: %s\n", ligne);
----------------------------------------------------------------------------
--------------------------------------
ret = (*env)->NewStringUTF(env, fmt);
return ret;
}

Many thanks.

Jean
 
R

Roedy Green

You have declared two different arrays "lettres". You don't initialize
the second one, which also happens to be the one seen inside the
native method.

Gordon was able to find all these problems just by eyeballing. He has
made these same errors himself many times before and now they stand
out like Christmas lights.

But what can you do to find them?

1. use Jikes. Its pedantic mode gives many lint warnings.
See http://mindprod.com/jgloss/jikes.html


2. Pepper your code with System.out.println so that you can assure
yourself that the code is doing what you think.

3. see http://mindprod.com/jgloss/debugger.html
 
Q

Québec

You have declared two different arrays "lettres". You don't initialize
Gordon was able to find all these problems just by eyeballing. He has
made these same errors himself many times before and now they stand
out like Christmas lights.

But what can you do to find them?

1. use Jikes. Its pedantic mode gives many lint warnings.
Jikes is not for java only?
Look at the end of the trail you will see I did something about it. Reading
etc, 'la référence du C' ~ 'C ansi from K&Ritctchie'
And solved some of the things there.

Jean
 
Q

Québec

/*
DEVC++
I did not succeed creating a working dll with DEV C++
dllwrap.exe --output-def libserial.def --implib libserial.a serie.o
serial_private.res -L"C:/Dev-Cpp/lib" -L"F:/unzipM_soft/w32api-2.0/lib" -L"C
:/jdk1.1.8/lib" -L"C:/jdk1.1.8/bin" -o serial.dll

dllwrap.exe: no export definition file provided.
Creating one, but that may not be what you want


but the borland linker char ligne[len]; <==Constant expression required
*/

fmt = (*env)->GetStringUTFChars(env, jstr, &iscopy);
len = (*env)->GetStringLength(env, jstr);

printf("The string received by C: %s has %d characters.\n", len, fmt);

const char *fmt = NULL;
char ligne[1];

fmt = (*env)->GetStringUTFChars(env, jstr, &iscopy);
len = (*env)->GetStringLength(env, jstr);
ligne[len];
printf("The string received by C: %s has %d characters.\n", fmt, len );


for(i=0;i<len;i++){
ligne = *(fmt+i);
printf("%d %c\n", i,ligne);
}
----------------

this is still a problem
ret = (*env)->NewStringUTF(env, (const char *)ligne);

Very styffy trail. At least, you wont think (if you can) I am not sleeping
onthe job.... I mean on the hobby.

Jean

Some of you guys ever seen my 'marvelous' paintings ? ;-)
http://web.jeanpierredaviau.com
 
Q

Québec

I hard coded the arrays because complains all the time for having a
constant. It does not accept char ligne[len];
I am sure the for loops are ok, I tested them in another non jni c file.
With or without ligne[12] = '\0'; the output is the same.
jstring does not have a '\0'. "" This means that Java VM UTF-8 strings
never have embedded nulls.

Here is the output:
..................
The string 'Jean Pierre' received by C has 11 characters.

fmt- e -80- Ï
fmt- e -80- Ï
fmt- e -80- Ï
fmt- 85- Ï

The string mixed by C is : [?om8§

in java: [?om8§
.......................................



Thanks

Jean
===========
#include "Serial.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#define JNI_FALSE 0
#define JNI_TRUE 1

char alphabet[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " <from a
friend on this group ...
"abcdefghijklmnopqrstuvwxyz_-";
const int alphas = sizeof alphabet - 1;


JNIEXPORT jstring JNICALL Java_Serial_numero
(JNIEnv *env, jobject jobjc, jstring jstr){
jboolean iscopy;
jstring ret;
jsize len;
int i, j;
const char *fmt;
char alphabet[65];
char ligne[12];

fmt = (*env)->GetStringUTFChars(env, jstr, &iscopy);
len = (*env)->GetStringLength(env, jstr);

printf("The string '%s' received by C has %d characters.\n", fmt, len );

for(i=0;i<11;i++){
for(j=0;j<alphas;j++){
if(alphabet[j] == fmt){
printf("fmt- %c ", fmt);
ligne = alphabet[65-j];
printf("%d- %c\n",ligne);
break;
}
}
}
ligne[12] = '\0';
printf("The string mixed by C is : %s\n", ligne);


ret = (jstring)(*env)->NewStringUTF(env, ligne);
(*env)->ReleaseStringUTFChars(env, jstr, fmt);

return ret;
}
=================
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Serial */

#ifndef _Included_Serial
#define _Included_Serial
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Serial
* Method: numero
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_Serial_numero
(JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif
===========

public class Serial
{ static
{
System.loadLibrary("serial");
}

public static void main(String[] args)
{
Serial serie = new Serial();
String fromC = serie.numero("Jean Pierre");
System.out.println("in java: " + fromC);
}

public native String numero(String one);

}
 
Q

Québec

At least there will be a working finalized code on that thread ;-)


#include "Serial.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#define JNI_FALSE 0
#define JNI_TRUE 1

char alphabet[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ "
"abcdefghijklmnopqrstuvwxyz_-";
const int alphas = sizeof alphabet - 1;


JNIEXPORT jstring JNICALL Java_Serial_numero
(JNIEnv *env, jobject jobjc, jstring jstr){
jthrowable exc;
jboolean iscopy;
jstring ret;
jsize len;
int i, j;
const char *fmt;
char ligne[11];

fmt = (*env)->GetStringUTFChars(env, jstr, &iscopy);
len = (*env)->GetStringLength(env, jstr);

printf("The string '%s' received by C has %d characters.\n", fmt, len );

for(i=0;i<11;i++){
for(j=0;j<alphas;j++){
if(alphabet[j] == fmt){
printf("%2d- %c ",i, fmt);
ligne = alphabet[65-j];
printf("%c\n", ligne);
/*printf( "Completed set, checking for exceptions..\n" );*/
exc = (*env)->ExceptionOccurred( env );
break;
}


}
}
ligne[11] = '\0';

printf("The string mixed by C is : %s\n", ligne);


ret = (jstring)(*env)->NewStringUTF(env, ligne);
(*env)->ReleaseStringUTFChars(env, jstr, fmt);
if (exc)
{
printf( "Exception detected..\n" );
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear(env);
}
return ret;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,778
Messages
2,569,605
Members
45,238
Latest member
Top CryptoPodcasts

Latest Threads

Top