如何解决PLC Latin1字符串经SWIG转Java的编码乱码问题?
解决PLC Latin1字符串转Java乱码问题(SWIG实现)
方案一:返回byte数组,Java端自行转码(推荐,无内存问题)
该方案针对getString函数单独配置SWIG类型映射,让它返回byte[]而非默认的String,Java端再用ISO-8859-1编码解析,完全避免编码转换的内存问题,且不影响其他char*类型的函数。
操作步骤:
- 在SWIG接口文件中,添加专属类型映射(放在
%extend SwigPara_pppPlcVarValue块之前):
// 仅对SwigPara_pppPlcVarValue的getString函数生效的类型映射 %typemap(jtype) char* SwigPara_pppPlcVarValue::getString "byte[]" %typemap(jstype) char* SwigPara_pppPlcVarValue::getString "byte[]" %typemap(jni) char* SwigPara_pppPlcVarValue::getString "jbyteArray" %typemap(out) char* SwigPara_pppPlcVarValue::getString { if ($1) { // 获取Latin1字符串长度 const size_t str_len = strlen((const char*)$1); // 创建Java字节数组 jbyteArray result_arr = jenv->NewByteArray(static_cast<jsize>(str_len)); // 将Latin1字节复制到数组中 jenv->SetByteArrayRegion(result_arr, 0, static_cast<jsize>(str_len), reinterpret_cast<const jbyte*>($1)); $result = result_arr; } else { $result = NULL; } }
保持原有的
%extend块不变,SWIG会自动生成返回byte[]的Java方法。Java端调用时,用ISO-8859-1编码解析字节数组:
byte[] latin1Bytes = swigPara.getString(index); String correctStr = new String(latin1Bytes, StandardCharsets.ISO_8859_1);
方案二:在SWIG中完成Latin1到UTF-8转换,自动管理内存
如果希望Java端直接拿到String,可以在getString函数中手动完成编码转换,并通过SWIG的%newobject标记让框架自动释放转换后的内存。
操作步骤:
- 修改
%extend块中的getString函数,添加%newobject标记并实现编码转换:
%extend SwigPara_pppPlcVarValue { // 标记返回的指针需要SWIG自动释放 %newobject getString(long index); char* getString(long index) { // 获取PLC返回的Latin1字符串 char* latin1_str = reinterpret_cast<char*>(&(self->ppChangedValues[index]->byData)); const size_t latin1_len = strlen(latin1_str); // 计算UTF-8所需的缓冲区大小(Latin1扩展字符转UTF-8占2字节) size_t utf8_len = 0; for (size_t i = 0; i < latin1_len; ++i) { const unsigned char c = static_cast<unsigned char>(latin1_str[i]); utf8_len += (c < 0x80) ? 1 : 2; } // 分配UTF-8缓冲区(+1用于字符串结束符) char* utf8_str = static_cast<char*>(malloc(utf8_len + 1)); if (!utf8_str) return nullptr; // 执行Latin1到UTF-8的转换 char* p = utf8_str; for (size_t i = 0; i < latin1_len; ++i) { const unsigned char c = static_cast<unsigned char>(latin1_str[i]); if (c < 0x80) { *p++ = c; } else { *p++ = 0xC0 | (c >> 6); *p++ = 0x80 | (c & 0x3F); } } *p = '\0'; // 添加字符串结束符 return utf8_str; } // 其他函数保持不变 bool getQuality(long index) {return self->ppChangedValues[index]->bQuality; } unsigned long getTimeStamp(long index) {return self->ppChangedValues[index]->ulTimeStamp; } // ... 剩余函数省略 };
- 重新生成SWIG代码,此时生成的JNI函数会自动调用
free释放转换后的UTF-8缓冲区,避免内存泄漏。Java端可直接调用getString获取正确字符串。
关键说明
- 方案一无需手动内存管理,更安全,适合大多数场景;
- 方案二需要自行实现编码转换,但Java端无需额外处理;
- 两种方案的类型映射都仅对
SwigPara_pppPlcVarValue::getString生效,不会影响其他返回char*的函数。
内容的提问来源于stack exchange,提问作者cProgrammer1992
相关产品推荐
相关产品推荐

