Question

I am currently developing an Android application which uses a native C library. I am very unfamiliar with C, and am having some conversion problems. I know that the problem has something to do with signed/unsigned numbers, but cannot figure out what I need to do to fix this.

The C library works fine on its own, and produces the correct results. However when I port it back to Android, only the positive values are correct. The negative values are returned as 256 minus the value.

For example:

 8 -> 8
 5 -> 5
 1 -> 1
 0 -> 0
-3 -> 253
-5 -> 251
-8 -> 248

This is what the C code looks like when it assigns the value:

BYTE *parms;
WORD __stdcall GetValue(BYTE what, long *val){

    char myStringParmsOne[255];
    sprintf( myStringParmsOne, "parms[1]=%d", parms[1] );
    LOG_INFO( myStringParmsOne );

    char myStringIsG[255];
    sprintf( myStringIsG, "API_isG=%d",API_isG );
    LOG_INFO( myStringIsG );

    char myStringCharParmsB[255];
    sprintf( myStringCharParmsB, "(char)parms[1]=%d", (char)parms[1] );
    LOG_INFO( myStringCharParmsB );

    *val=(char)parms[1]-(API_isG?11:0);
}

The LOG_INFO statements print the values to LogCat. Below I have values when the program is run and a value of -3 is expected.

The first **parms[1]=%d** statement returns **parms[1]=253**

The second **API_isG=%d** statement returns **API_isG=0**

The third **(char)parms[1]=%d** statement returns **(char)parms[1]=253**

The BYTE and WORD types are defined as follows:

typedef unsigned char BYTE;
typedef unsigned short WORD;

The wrapper function I use to send this value back to Java is shown below:

long Java_my_package_Model_00024NativeCalls_GetValueJava( JNIEnv *env, jobject obj, WORD what) {
    long c;
    int j = GetValue( what, &c );
    if( j == 0 ) {
        return c;
    } else {
        return -1;
    }
}

EDIT

The GetValue method is used all the time, but only this individual call gives me problems with negative numbers, it works with other calls. I have tried the two following things for my wrapper function:

long Java_my_package_Model_00024NativeCalls_GetValueJava( JNIEnv *env, jobject obj, WORD what) {
    long c;
    int j = GetValue( what, &c );
    if( j == 0 ) {
        return (signed char)c;
    } else {
        return -1;
    }
}

The casting of the return value above provides me with a proper return value. However, all of the other calls to this function for other values are completely haywire.

long Java_my_package_Model_00024NativeCalls_GetValueJava( JNIEnv *env, jobject obj, WORD what) {
    long c;
    int j = GetValue( what, &c );
    if( j == 0 ) {
        return (signed long)c;
    } else {
        return -1;
    }
}

The above casting of the return value changed nothing.

Was it helpful?

Solution

This happens because you are putting an unsigned char (IIRC in NDK char is unsigned by default) inside a long. If the value you put inside the long was signed then the compiler would have changed also the sign bit of the long.

Try to change the cast from

*val=(char)parms[1]-(API_isG?11:0);

to

*val=(long)((signed char)parms[1]-(API_isG?11:0));

(not sure if the (long) cast is required, maybe the cast to (signed char) is enough.

OTHER TIPS

Change the types from unsigned char/unsigned short to char/short if you want to store signed values.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top