JNI reinterpret_cast 的替代方案?

Alternative to reinterpret_cast for JNI?

我正在关注我的 Android 应用程序和我的 C++ 库之间的 Google tips to implement a JNI layer。建议在库加载时使用如下代码注册native方法:

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }

    ...

    // Register your class' native methods.
    static const JNINativeMethod methods[] = {
        {"nativeFoo", "()V", reinterpret_cast<void*>(nativeFoo)},
        {"nativeBar", "(Ljava/lang/String;I)Z", reinterpret_cast<void*>(nativeBar)},
    };
    int rc = env->RegisterNatives(c, methods, sizeof(methods)/sizeof(JNINativeMethod));
    ...
}

我对 C++ 还很陌生,所以我决定使用 clang-tidy 来确保我的 C++ 代码现代且安全。 clang-tidy 报告:

error: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast,-warnings-as-errors]

根据 clang-tidy documentation:

cppcoreguidelines-pro-type-reinterpret-cast

This check flags all uses of reinterpret_cast in C++ code.

Use of these casts can violate type safety and cause the program to access a variable that is actually of type X to be accessed as if it were of an unrelated type Z.

This rule is part of the “Type safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-reinterpretcast.

所以我有几个选择:

  1. 禁用此检查并冒着在其他地方不恰当地使用 reinterpret_cast 的风险
  2. 在我需要使用它的地方忽略检查并创建一个混乱的代码库
  3. 找到一些更安全的替代方法

如果可能的话,我想做 3,但我不太确定从哪里开始。

不清楚 为什么 GetEnv 想要 void** 而不是 JNIEnv**(您会使用其他什么类型?),但是您可以使用 temporary 变量来避免 reinterpret_cast 和伴随的未定义行为(!):

void *venv;
if (vm->GetEnv(&venv, JNI_VERSION_1_6) != JNI_OK) {
    return JNI_ERR;
}
const auto env=static_cast<JNIEnv*>(venv);

注意 static_cast from void*reinterpret_cast 一样危险,但它在这里的使用是正确的,不可避免的,并且不应产生 linter 警告。

在函数指针的情况下没有什么可做的:reinterpret_cast 是唯一正确的选择(对于 void* 而不是某些占位符 functionvoid (*)() 这样的指针类型,它的正确性不是 C++ 保证的 ,尽管它广泛工作并且 POSIX 确实保证了它)。您当然可以在函数(模板)中隐藏该转换,以便告诉 linter 仅忽略它,但请确保使用清晰的名称以避免“隐藏”转换。