You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决PLC Latin1字符串经SWIG转Java的编码乱码问题?

解决PLC Latin1字符串转Java乱码问题(SWIG实现)

方案一:返回byte数组,Java端自行转码(推荐,无内存问题)

该方案针对getString函数单独配置SWIG类型映射,让它返回byte[]而非默认的String,Java端再用ISO-8859-1编码解析,完全避免编码转换的内存问题,且不影响其他char*类型的函数。

操作步骤:

  1. 在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;
  }
}
  1. 保持原有的%extend块不变,SWIG会自动生成返回byte[]的Java方法。

  2. 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标记让框架自动释放转换后的内存。

操作步骤:

  1. 修改%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; }
  // ... 剩余函数省略
};
  1. 重新生成SWIG代码,此时生成的JNI函数会自动调用free释放转换后的UTF-8缓冲区,避免内存泄漏。Java端可直接调用getString获取正确字符串。

关键说明

  • 方案一无需手动内存管理,更安全,适合大多数场景;
  • 方案二需要自行实现编码转换,但Java端无需额外处理;
  • 两种方案的类型映射都仅对SwigPara_pppPlcVarValue::getString生效,不会影响其他返回char*的函数。

内容的提问来源于stack exchange,提问作者cProgrammer1992

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:59:50