在JNI中,能否将C整数参数传递给Java原语int?

在JNI中,能否将C整数参数传递给Java原语int?,java,java-native-interface,Java,Java Native Interface,我有一个Java方法,希望从一些本机方法调用: public void onDownloadProgress(int current, int total) { } int current = ... int total = ... jni_callVoidMethod( env, jDownloadCallback, "onDownloadProgress", "(II)V",

我有一个Java方法,希望从一些本机方法调用:

    public void onDownloadProgress(int current, int total) {

    }
    int current = ...
    int total = ...
    jni_callVoidMethod(
        env,
        jDownloadCallback,
        "onDownloadProgress",
        "(II)V",
        current,
        total
    );
我试图从本机方法调用上述Java方法:

    public void onDownloadProgress(int current, int total) {

    }
    int current = ...
    int total = ...
    jni_callVoidMethod(
        env,
        jDownloadCallback,
        "onDownloadProgress",
        "(II)V",
        current,
        total
    );
jni_callVoidMethod是一种辅助方法,其实现是:

    void jni_callVoidMethod(JNIEnv *env, jobject receiver, const char *methodName, const char *contract, ...) {
        jclass clazz = env->GetObjectClass(receiver);
            if (NULL != clazz) {
            jmethodID method = env->GetMethodID(
            clazz,
            methodName,
            contract
        );
        if (NULL != method) {
            BUILD_VARARGS()
                env->CallVoidMethodV(
                receiver,
                method,
                va_args
            );
        if (env->ExceptionCheck()) { // prints out the exception if one is present
            env->ExceptionDescribe();
            env->ExceptionClear();
        }
        va_end(va_args);
        }
        env->DeleteLocalRef(clazz);
    }
}
然而,在Java方法中,我得到了一些非常奇怪的int值。例如,384012912。我想知道您是否可以直接向Java原语int发送一个C int,而不是将Java方法中的参数声明为整数类型?将这两个参数声明为整数对我来说很有效,我得到了正确的值

编辑: 构建变量的实现宏:

#define BUILD_VARARGS() \
va_list va_args; \
va_start(va_args, contract); \
const char *cur = contract; \
while ('\0' != *cur && '(' != *cur) { /* skip to opening paren */ \
    cur++; \
} \
while ('\0' != *cur && ')' != *cur) { /* stop at closing paren */ \
    switch (*cur) { \
        case 'Z': \
            va_arg(va_args, int); /* bool (unsigned 8-bit int) */ \
            break; \
        case 'B': \
            va_arg(va_args, int); /* byte (signed 8-bit int) */ \
            break; \
        case 'C': \
            va_arg(va_args, int); /* char (unsigned 16-bit int) */ \
            break; \
        case 'S': \
            va_arg(va_args, int); /* short (signed 16-bit int) */ \
            break; \
        case 'I': \
            va_arg(va_args, long long); /* int (signed 32-bit int) (must be passed in as a long long) */ \
            break; \
        case 'J': \
            va_arg(va_args, long); /* long (signed 64-bit int) */ \
            break; \
        case 'F': \
            va_arg(va_args, double); /* float (32 bits) */ \
            break; \
        case 'D': \
            va_arg(va_args, double); /* double (64 bits) */ \
            break; \
        case 'L': \
            /* fully-qualified-class */ \
            while (';' != *++cur && '\0' != *cur); /* advance to end of class declaration */ \
            /* FIXME breaks varargs, seems to not be needed va_arg(va_args, jobject); */ \
            break; \
        case '[': \
            /* TODO type type[] */ \
        case '(': \
            /* TODO ( arg-types ) ret-type  method type */ \
        default: \
            break; \
    } \
    cur++; \
}

这就解释了一切!对
va_arg
的调用使用参数,当
CallVoidMethodV
到达它时,它正在从堆栈中的其他地方读取。从
va_arg
手册:

va_arg()宏将扩展为具有类型和值的表达式 调用中的下一个参数。参数ap是va_列表ap 由va_start()初始化。
每次调用va_arg()都会修改ap,以便 下一个调用返回下一个参数。

相反,您应该创建
va_列表
,并立即将其交给
CallVoidMethodV

va_list va_args;
va_start(va_args, contract);
env->CallVoidMethodV(receiver, method, va_args);
va_end(va_args);

这就解释了一切!对
va_arg
的调用使用参数,当
CallVoidMethodV
到达它时,它正在从堆栈中的其他地方读取。从
va_arg
手册:

va_arg()宏将扩展为具有类型和值的表达式 调用中的下一个参数。参数ap是va_列表ap 由va_start()初始化。
每次调用va_arg()都会修改ap,以便 下一个调用返回下一个参数。

相反,您应该创建
va_列表
,并立即将其交给
CallVoidMethodV

va_list va_args;
va_start(va_args, contract);
env->CallVoidMethodV(receiver, method, va_args);
va_end(va_args);

试一试
jni_callVoidMethod(env,”(II)V“,(jint)current,(jint)total)。我猜您使用的是64位
int
,但Java接受它们作为32位值,这会破坏堆栈。如果问题是@vbezhenar建议的那样,在您的C代码中,您可以
#包含
,并对C中的变量使用
int32\t
而不是
int
。@vbezhenar,我尝试了您的建议,但没有成功。我硬编码了int current=1和int total=413,在Java中,我从current得到366961048,从total得到375649488。那么jni_CallVoidMethod从何而来?您是否可以先尝试不使用它,即直接调用
GetObjectClass
GetMethodID
CallVoidMethod
(不带“V”)。这样你就不会有弄乱varargs的风险。我猜您使用的是64位
int
,但Java接受它们作为32位值,这会破坏堆栈。如果问题是@vbezhenar建议的那样,在您的C代码中,您可以
#包含
,并对C中的变量使用
int32\t
而不是
int
。@vbezhenar,我尝试了您的建议,但没有成功。我硬编码了int current=1和int total=413,在Java中,我从current得到366961048,从total得到375649488。那么jni_CallVoidMethod从何而来?您是否可以先尝试不使用它,即直接调用
GetObjectClass
GetMethodID
CallVoidMethod
(不带“V”)。这样你就不用冒把瓦拉格家搞砸的风险了。非常感谢!非常感谢你!