简体   繁体   English

ESP8266从char数组获取垃圾数据

[英]ESP8266 getting garbage data from char array

I'm honestly at a loss here. 老实说,我在这里很茫然。 I'm trying to store an SSID and password that the user sends through a post request in the flash EEPROM section. 我正在尝试将用户通过发布请求发送的SSID和密码存储在Flash EEPROM部分中。 To do that I convert the data sent from the post request to a char array and index it to EEPROM. 为此,我将从发布请求发送的数据转换为char数组并将其索引到EEPROM。 The SSID runs without any problems, but the password always ends up with junk data before it even gets to EEPROM. SSID可以正常运行,但是密码在进入EEPROM之前总是以垃圾数据结尾。 Here is the bit of code in question: 这是有问题的代码:

// Recieve data from the HTTP server
void changeConfig(String parameter, String value){
  int memoffset = 0;
  if(parameter == "ssid")
    memoffset = 0;
  else if(parameter == "pass")
    memoffset = 32;
  else
    return;
  #ifdef DEBUG
  Serial.println("Updating Data");
  Serial.print("Param: ");
  Serial.println(parameter);
  Serial.print("Value: ");
  Serial.println(value);
  #endif
  EEPROM.begin(64);
  char _data[sizeof(value)];
  value.toCharArray(_data, sizeof(value));
  for(int i = memoffset; i < memoffset + sizeof(value); i++)
  {
    #ifdef DEBUG
      Serial.print("addr ");
      Serial.print(i);
      Serial.print(" data ");
      Serial.println(_data[i]);
      #endif 
      EEPROM.write(i,_data[i]);
  }
  EEPROM.end();
}

And the Serial monitor output: 和串行监视器输出:
Post parameter: ssid, Value: NetworkName 发布参数:ssid,值:NetworkName
Updating Data 更新数据
Param: ssid 参数:ssid
Value: NetworkName 值:NetworkName
addr 0 data N 地址0数据N
addr 1 data e 地址1数据e
addr 2 data t 加法器2数据t
addr 3 data w 地址3数据w
addr 4 data o 地址4数据o
addr 5 data r 地址5数据r
addr 6 data k 加法器6数据k
addr 7 data N 地址7数据N
addr 8 data a 地址8数据a
addr 9 data m 地址9数据m
addr 10 data e 地址10数据e
addr 11 data ␀ 地址11数据␀
Post parameter: pass, Value: Networkpass 发布参数:通过,值:Networkpass
Updating Data 更新数据
Param: pass 参数:通过
Value: Networkpass 值:Networkpass
addr 32 data | addr 32数据|
addr 33 data ( 地址33数据(
addr 34 data 地址34数据
addr 35 data ? 地址35数据?
addr 36 data L 加法器36数据L
addr 37 data ␛ 地址37数据␛
addr 38 data 地址38数据
addr 39 data ? addr 39数据?
addr 40 data ␁ 地址40数据␁
addr 41 data ␀ 地址41数据␀
addr 42 data ␀ 地址42数据␀
addr 43 data ␀ 地址43数据␀

As you can see, when the name of the POST parameter is ssid, it works alright. 如您所见,当POST参数的名称为ssid时,它可以正常工作。 With pass on the other hand, the char array is just filled with gibberish. 另一方面,通过pass时,char数组只是充满了乱码。 Any insight would be helpful. 任何见解都会有所帮助。 I'm using platformio in the arduino environment. 我在arduino环境中使用platformio。 Generic ESP01 with 1M of flash. 具有1M闪存的通用ESP01。 Thanks in advance. 提前致谢。

You have two problems with your code. 您的代码有两个问题。

First, you are using sizeof incorrectly. 首先,您使用的sizeof错误。 Sizeof returns the size of the String object, but you are trying to get the length of the contained string. Sizeof返回String对象的大小,但是您正在尝试获取所包含字符串的长度。 Sizeof is not the right tool for that, instead you should use whatever API String offers to read the size of the string. Sizeof不是正确的工具,而是应该使用API String提供的任何内容来读取字符串的大小。

The next problem is your usage of offsets. 下一个问题是偏移量的用法。 The following code snippet is all wrong: 以下代码段都是错误的:

char _data[sizeof(value)];
value.toCharArray(_data, sizeof(value));
for(int i = memoffset; i < memoffset + sizeof(value); i++)
{
  ...
  EEPROM.write(i,_data[i]);

Your i starts with offset of 32, so you are trying to access element with index 32 in your _data array. 您的i以32的偏移量开头,因此您正在尝试访问_data数组中索引为32的元素。 But _data stores characters starting from the index 0, and since the length of array is actually 12 (sizeof of String is always 12) by accessing element with index 32 you are going beyond it's bounds, and obviously find garbage there (in C++ parlance, it is called undefined behavior). 但是_data存储从索引0开始的字符,由于数组的长度实际上是12( String sizeof始终为12),因此通过访问索引为32的元素,您已经超出了它的范围,并且显然在那里找到了垃圾(用C ++的说法,这称为未定义行为)。

Last, but not the least, C++ is an extremely complicated language, which can't be learned by 'trial and error'. 最后但并非最不重要的一点是,C ++是一种极其复杂的语言,无法通过“反复试验”来学习。 Instead, you need to methodically study, preferably using one of the good C++ books. 相反,您需要系统地学习,最好使用一本优秀的C ++书籍。 The list of those can be found here: The Definitive C++ Book Guide and List 这些的列表可以在这里找到: 权威的C ++书籍指南和列表

You're using sizeof() incorrectly. 您使用的sizeof()错误。

sizeof() tells you the size of the object, at compile time. sizeof()告诉您在编译时对象的大小。

Try this experiment - run this code: 尝试此实验-运行以下代码:

#include <Arduino.h>

void setup() {
  String x("");
  String y("abc");
  String z("abcdef");

  Serial.begin(115200);

  delay(1000);

  Serial.println(sizeof(x));
  Serial.println(sizeof(y));
  Serial.println(sizeof(z));
}

void loop() {
}

On my ESP8266 this outputs: 在我的ESP8266上,输出:

12
12
12

That's because it takes 12 bytes using this development environment to represent a String object (it might be different on a different CPU and compiler). 这是因为使用此开发环境需要12个字节来表示String对象(在不同的CPU和编译器上可能有所不同)。 The String class dynamically allocates storage, so sizeof can tell you nothing about how long the string itself is, only the compile-time size of the object. String类动态分配存储空间,因此sizeof不能告诉您字符串本身有多长时间,只有对象的编译时大小。

For the String class, you should use its length() method. 对于String类,应使用其length()方法。 Your lines: 您的台词:

char _data[sizeof(value)];
value.toCharArray(_data, sizeof(value));
for(int i = memoffset; i < memoffset + sizeof(value); i++)

should be written as 应该写成

char _data[value.length()];
value.toCharArray(_data, value.length());
for(int i = memoffset; i < memoffset + value.length(); i++)

For more information see the documentation on the String class . 有关更多信息,请参见String类文档

You'll likely still have issues with string terminators. 字符串终止符可能仍然存在问题。 C and C++ terminate char array strings with the null character '\\0', adding an extra byte to the length of the strings. C和C ++以空字符'\\ 0'终止char数组字符串,从而在字符串的长度上增加了一个额外的字节。 So your code should more likely be: 因此,您的代码应该更可能是:

void changeConfig(String parameter, String value){
  int memoffset = 0;
  if(parameter == "ssid")
    memoffset = 0;
  else if(parameter == "pass")
    memoffset = 33;
  else
    return;
  #ifdef DEBUG
  Serial.println("Updating Data");
  Serial.print("Param: ");
  Serial.println(parameter);
  Serial.print("Value: ");
  Serial.println(value);
  #endif
  EEPROM.begin(66);
  char _data[value.length() + 1];
  value.toCharArray(_data, value.length() + 1);
  for(int i = memoffset; i < memoffset + value.length() + 1; i++)
  {
    #ifdef DEBUG
      Serial.print("addr ");
      Serial.print(i);
      Serial.print(" data ");
      Serial.println(_data[i]);
      #endif 
      EEPROM.write(i,_data[i]);
  }
  EEPROM.end();
}

to allow the string terminators to work correctly for 32 character SSIDs and passwords. 以使字符串终止符对于32个字符的SSID和密码能够正常工作。 But the fundamental issue that's breaking your code is the incorrect use of sizeof . 但是,破坏代码的根本问题是对sizeof的错误使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM