JNI遇到error: request for member ‘FindClass‘ in something not a structure or union

本文详细解析了JNI错误处理中关于JNIEnv引用的问题,并着重讨论了在C/C++编译环境下正确引用JNIEnv的方法。文章还介绍了如何在代码中实现C/C++的兼容性,以避免出现找不到特定JNI方法的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介:

本篇通过一个jni错误,来说明c/c++编译器在处理jni代码时,引用到JNIEnv时的注意事项。

1. 问题描述:

在调试jni代码时,出现如下错误:error: request for member 'FindClass' in something not a structure or union

2. 分析:

从错误信息可以看出,找不到FindClass。但是,FindClass是jni中env标准的方法呀,怎么会找不到?再仔细一想,env不可能没有FindClass,除非env本身没有被正确引用。

3. 关于jni中env的简单介绍:

jni中的env,即JNIEnv_(c++) 或 JNINativeInterface_(c),声明在jni.h中, 如下:

jni.h代码截取:

详情可以参考:jni.h Source File

struct JNINativeInterface_;

struct JNIEnv_;

#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv;
#endif

......
struct JNINativeInterface_ {
     void *reserved0;
     void *reserved1;
     void *reserved2;
 
     void *reserved3;
     jint (JNICALL *GetVersion)(JNIEnv *env);
 
     jclass (JNICALL *DefineClass)
       (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,
        jsize len);
     jclass (JNICALL *FindClass)
       (JNIEnv *env, const char *name);

......
};

/*
* We use inlined functions for C++ so that programmers can write:
*
*   env->FindClass("java/lang/String")
*
* in C++ rather than:
*
*    (*env)->FindClass(env, "java/lang/String")
*
* in C.
*/

 struct JNIEnv_ {
     const struct JNINativeInterface_ *functions;
 #ifdef __cplusplus
 
     jint GetVersion() {
         return functions->GetVersion(this);
     }
     jclass DefineClass(const char *name, jobject loader, const jbyte *buf,
                jsize len) {
         return functions->DefineClass(this, name, loader, buf, len);
     }
     jclass FindClass(const char *name) {
         return functions->FindClass(this, name);
     }

......
 #endif /* __cplusplus */
 };

注释已经明确说明,在使用方式上的区别:

如果是C++要用 env->FindClass("java/lang/String")

如果是c程序,要用 (*env)->FindClass(env, "java/lang/String")


所以,在linux下如果.c文件中用 “env->” 编译会找不到此结构,必须用“(*env)->”,或者改成.cpp文件,以 c++的方式来编译。

同理,ReleaseStringUTFChars函数也有可能出现这样的问题。

4. c/c++的兼容方式:

在代码中也可以看到,用如下的宏指令来进行c/c++的兼容:
 

#ifdef __cplusplus
 ......

 #else

 ......

 #endif
下面,是一个典型的自定义.h头文件:
#include <jni.h>
#ifndef _Included_com_a_b_Utils
#define _Included_com_a_b_Utils

#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jboolean   JNICALL Java_com_a_b_Utils_setConfig(JNIEnv*, jclass, jboolean enabled);
JNIEXPORT jboolean   JNICALL Java_com_a_b_Utils_getConfig(JNIEnv*, jclass);
#ifdef __cplusplus
}
#endif

#endif

在进行代码开发时,想一想你的系统是否需要做兼容。

<think>首先,用户的问题是关于C++编译错误:"error: member reference base type 'const char [21]' is not a structure or union"。我需要根据系统级指令来构建我的回答。 系统级指令要求: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题,保证回答真实可靠。 用户的问题是关于C++错误:"member reference base type 'const char [21]' is not a structure or union"。这表示用户试图访问一个成员(如点运算符或箭头运算符),但基类型是'const char [21]',这不是一个结构体或联合体。 回顾参考引用: - 引用[1]:错误"request for member ‘i’ in ‘data’, which is of non-class type ‘float’"。 - 引用[2]:关于std::is_class_v的C++17特性。 - 引用[3]:JNI相关错误和资源编译配置。 用户意图是解决这个错误。错误的核心是:用户使用了点运算符(.)或箭头运算符(->)在一个不是结构体或联合体的类型上。 常见原因: 1. 用户可能误用了运算符,比如在数组上使用点运算符。 2. 可能混淆了指针和对象。 3. 可能错误地访问了字符串字面量的成员。 例如,用户可能有代码如: ```cpp const char* str = "Hello World"; int len = str.length(); // 错误,因为str是const char*,不是类类型 ``` 正确的方式是使用strlen函数或使用std::string。 解决步骤: 1. 识别错误位置:找出在代码中哪里使用了点运算符或箭头运算符在一个非类类型上。 2. 检查类型:确认变量或表达式的类型。 3. 修正代码:如果类型是基本类型或数组,使用正确的访问方式。 在回答中,我需要结构化: - 解释错误原因。 - 提供示例。 - 给出解决方案。 - 生成相关问题。 由于问题涉及C++类型,我可以使用std::is_class_v来检查类型,如引用[2]所述。 生成相关问题: - 类似错误的其他变体。 - C++中类型系统的其他方面。 - 如何避免此类错误。 确保使用中文回答。 最终回答结构: 1. 解释错误。 2. 分析原因。 3. 提供解决方案和示例。 4. 生成相关问题。</think>### C++ 编译错误分析:error: member reference base type 'const char [21]' is not a structure or union 您遇到的错误 `error: member reference base type 'const char [21]' is not a structure or union` 是 C++ 编译器中常见的类型错误。它表示您试图使用点运算符(`.`)或箭头运算符(`->`)访问一个成员(如方法或属性),但基类型是 `const char [21]`(一个常量字符数组),而不是结构体(`struct`)或联合体(`union`)。这类错误通常源于类型不匹配或运算符误用。下面我将逐步解释原因并提供解决方案。 #### 错误原因分析 1. **类型不匹配**: - `const char [21]` 是一个固定大小的字符数组(例如字符串字面量),它不是类类型(class type)。在 C++ 中,只有类类型(如结构体、类、联合体)支持成员访问运算符(`.` 或 `->`)。 - 例如,如果您写 `"Hello World".length()`,编译器会报错,因为 `"Hello World"` 的类型是 `const char[12]`,不是类类型[^1]。 - 数学类比:就像试图在标量上使用向量运算符,例如 $ \vec{a} \cdot \vec{b} $ 要求 $\vec{a}$ 和 $\vec{b}$ 都是向量,但如果 $\vec{a}$ 是标量(如整数),操作就会失败。 2. **常见触发场景**: - **误用字符串字面量**:直接在字符串上调用方法,如 `"example".size()`。 - **指针处理错误**:将字符指针(`char*`)当作对象使用,如 `char* str = ...; str.length();`。 - **类型推导问题**:编译器将变量推导为基本类型而非类类型,例如使用 `auto` 时未注意实际类型[^2]。 #### 解决方案与示例 解决此错误的关键是确保成员访问运算符只用于类类型对象。以下是具体步骤和代码示例: 1. **使用 `std::string` 替代字符数组**: - 标准库的 `std::string` 是类类型,支持成员方法如 `length()` 或 `size()`。 - 错误示例: ```cpp #include <iostream> int main() { const char str[21] = "Hello World"; // 类型为 const char[21] int len = str.length(); // 错误!str 不是类类型 return 0; } ``` - 修正后: ```cpp #include <iostream> #include <string> // 引入 string 头文件 int main() { std::string str = "Hello World"; // 使用 std::string int len = str.length(); // 正确:str 是类类型 std::cout << "Length: " << len << std::endl; // 输出 11 return 0; } ``` 2. **检查变量类型**: - 使用 `std::is_class_v`(C++17 或更高版本)编译时检查类型是否为类类型[^2]。 ```cpp #include <iostream> #include <type_traits> int main() { const char arr[21] = "Test"; std::cout << std::boolalpha; std::cout << "Is arr a class? " << std::is_class_v<decltype(arr)> << std::endl; // 输出 false return 0; } ``` - 如果输出 `false`,说明变量不是类类型,应避免成员访问。 3. **处理指针和数组**: - 字符指针(`char*`)或数组不支持成员方法,需用 C 风格函数如 `strlen()`。 - 错误示例: ```cpp const char* ptr = "Pointer Example"; int len = ptr->size(); // 错误!ptr 是指针,但指向的类型不是类 ``` - 修正后: ```cpp #include <cstring> // 引入 strlen #include <iostream> int main() { const char* ptr = "Pointer Example"; int len = strlen(ptr); // 正确:使用 C 风格函数 std::cout << "Length: " << len << std::endl; // 输出 15 return 0; } ``` 4. **避免运算符误用**: - 确保点运算符只用于对象实例,箭头运算符只用于指针指向的对象。 - 例如,如果 `obj` 是类实例,用 `obj.method()`;如果 `ptr` 是指向类的指针,用 `ptr->method()`。 #### 预防措施 - **启用编译器警告**:编译时添加 `-Wall -Wextra`(GCC/Clang)或 `/W4`(MSVC),帮助提前发现类型问题。 - **使用现代 C++ 特性**:优先使用 `std::string` 而非字符数组,减少错误风险。 - **代码审查**:检查所有成员访问操作,确认基类型是类类型(可用 `std::is_class_v` 验证)[^2]。 如果问题仍未解决,请提供相关代码片段,我会进一步分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liranke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值