You need to enable JavaScript to run this app. Arduino函数返回长度未知字符数组时编码结果为空的排查
优惠活动
大模型
产品
解决方案
定价
更多

Arduino函数返回长度未知字符数组时编码结果为空的排查

问题定位与修正方案

核心故障根源

  • 当前函数对形参的操作完全无法影响调用侧的变量,本质是C/C++的值传递规则导致的:
    你定义的generateData(char* encoded)形参,只是函数栈上的一个临时指针副本,调用时把调用侧char* encoded的随机值拷贝给这个临时形参。函数内部通过malloc给这个临时形参赋值的操作,完全不会修改调用侧原本的encoded指针。函数执行结束后,栈上的临时形参直接销毁,调用侧的encoded始终是未初始化的野指针,读取它指向的内容自然为空、为乱码;后续对这个野指针执行free()操作,还会触发未定义内存行为,导致设备随机死机。

其他潜在实现隐患

  • 变长数组(VLA)兼容性风险:代码中byte plain[inputString.length() + 1]属于C99规范的变长栈分配语法,在Arduino常用的AVR/ESP8266/ESP32 C编译环境下不属于标准C特性,容易出现栈溢出、内存长度计算错误的问题,尤其在RAM资源有限的嵌入式设备上,栈空间被动态分配占满后极易触发硬故障。
  • 加密长度计算偏差:des.calc_size_n_pad(sizeof(plain))的传值逻辑存在隐患,依赖VLA的运行期sizeof计算,一旦编译器对VLA的实现存在差异,传入的加密长度会完全错误,导致后续加密流程越界。
  • 无内存分配失败判断:嵌入式设备堆内存容量极小,malloc返回NULL的概率远高于桌面系统,当前代码完全不判断分配结果就直接写入内存,会直接触发内存访问异常。

代码修正方案

第一步:修正指针传递逻辑

有两种符合C/C++规范的写法,推荐第二种更不容易出错:

  1. 二级指针传参,将堆内存地址写回调用侧
    修改函数定义为接收二级指针:
    int generateData(char** encoded) {
      // ... 中间的JSON拼接、DES加密逻辑不变
      // 仅修改内存赋值的代码段
      int inputLength = des.get_size();
      int newLength = Base64.encodedLength(inputLength);
      *encoded = (char*)malloc(newLength + 1);
      // 必须增加分配失败判断
      if (*encoded == NULL) {
        return 0;
      }
      (*encoded)[newLength] = '\0';
      Base64.encode(*encoded, (char*)encodedByte, inputLength);
      return newLength;
    }
    
    调用侧修改为传入指针地址,同时初始化原指针为NULL:
    char* encoded = NULL;
    int contentLength = generateData(&encoded);
    // ... 后续的网络发送逻辑不变
    free(encoded); // 分配失败时free(NULL)是安全的,无异常
    
  2. 更简洁的返回值传指针写法,避免二级指针的使用复杂度
    将函数调整为返回堆内存指针,通过出参传递数据长度:
    char* generateData(int* outContentLength) {
      // ... 中间逻辑不变
      char* encoded = (char*)malloc(newLength + 1);
      if (encoded == NULL) {
        *outContentLength = 0;
        return NULL;
      }
      encoded[newLength] = '\0';
      Base64.encode(encoded, (char*)encodedByte, inputLength);
      *outContentLength = newLength;
      return encoded;
    }
    
    调用侧代码:
    int contentLength;
    char* encoded = generateData(&contentLength);
    // ... 后续网络发送逻辑不变
    free(encoded);
    

第二步:移除VLA风险,替换为安全的动态内存分配

把原代码中栈上的变长数组全部替换为堆分配,使用完成后及时释放临时内存:

// 原VLA代码替换为:
size_t plainLen = inputString.length() + 1;
byte* plain = (byte*)malloc(plainLen);
inputString.getBytes(plain, plainLen);
des.calc_size_n_pad(plainLen); // 传入实际数据长度,不依赖sizeof
size_t desSize = des.get_size();
byte* encodedByte = (byte*)malloc(desSize);
byte* plain_p = (byte*)malloc(desSize);

// ... 加密流程逻辑不变

// 加密、Base64编码全部完成后,及时释放临时内存
free(plain);
free(plain_p);
free(encodedByte);

第三步:修正Content-Length计算逻辑

你当前代码中contentLength +5是固定拼接data=前缀的长度,要确保该值和实际发送的请求体总长度完全一致,否则服务器会截断请求体或等待超时。


内容的提问来源于stack exchange,提问作者Luuk D. Jansen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.04 02:45:05