缓冲区被覆盖

Buffer gets overwritten

我在 ESP8266(类似 Arduino 的板)上遇到这个问题,但这个问题是关于 c/c++,所以我在这里问这个。

我对像 c/c++ 这样的母语没有太多经验,而且我面临一个奇怪的问题,这让我发疯。所以我使用的是 Wemos D1 mini (ESP8266),它使用 class calles ConfigManager 从 eeprom 读取配置文件。配置文件的格式为 json,因此我使用 ArduinoJson 来解析内容。我在 header 中声明了 StaticJsonBuffer 和指向 JsonObject 的指针,就像您在代码示例中看到的那样:

//FILE: ConfigManager.h
#ifndef ConfigManager_H
#define ConfigManager_H

#include <Arduino.h>
#include <ArduinoJson.h>
#include <FS.h>
#include "Logger.h"

class ConfigManager {
public:

    Settings *settings;  

    ConfigManager();

    void read_from_eeprom();

private:

    File configFile;
    JsonObject *json;
    StaticJsonBuffer<200> jsonBuffer;

    void open_file(const char *permission);

    void read_json();

    void recreate_file();

    void create_json();

    void check_success();

    void populate_settings();

    void clean_up();
};

#endif

调用函数read_from_eeprom时,打开文件并调用函数read_json:

void ConfigManager::read_json() {
    size_t size = configFile.size();
    Log.verbose("[ConfigManager] Config file size: %d", size);

    std::unique_ptr<char[]> buf(new char[size]);
    configFile.readBytes(buf.get(), size);
    Log.verbose("[ConfigManager] File content: %s", buf.get());

    Log.verbose("[ConfigManager] Parsing json");
    json = &jsonBuffer.parseObject(buf.get());

    Log.notice("[ConfigManager] Json is:");
    json->printTo(Serial);
    Serial.println();
}

随后调用 check_success()

void ConfigManager::check_success() {
    Log.notice("[ConfigManager] Json is:");
    json->printTo(Serial);
    Serial.println();


    bool should_recreate = true;
    if (json->success()) {
        Log.notice("[ConfigManager] Parsed json successfully");

        auto version = json->get<const char*>("version");
        if (version) {
            if (strcmp(version, Settings::current_version) == 0) {
                Log.notice("[ConfigManager] Config version is up2date");
                should_recreate = false;
            } else {
                Log.warning("[ConfigManager] Config version outdated");
            }
        } else {
            Log.warning("[ConfigManager] Invalid config file");
        }
    } else {
        Log.warning("[ConfigManager] Config file is not valid json");
    }

    if (should_recreate) {
        Log.notice("[ConfigManager] Recreating config file");
        recreate_file();
        create_json();
    }

    Log.notice("JSON IS: ");
    json->prettyPrintTo(Serial);

    Log.notice("[ConfigManager] Sucessfully read json");
}

所以我注意到文件内容没问题。例如。 {"version":"0.2","led_count":"64"}

然后 json 被解析,这成功并记录了 json object,这又是 {"version":"0.2","led_count":"64"}

之后函数returns,调用check_success,再次打印json object的内容到日志,但是这次好像有什么覆盖了 JsonBuffer,导致 json object 被破坏。这次记录的内容是{"v␂":"0.2","led_count":"64"}(带有一些奇怪的独角兽字符,随着源代码的变化而变化)。我试图弄清楚现在好几个小时发生了什么,但我被困住了。有人可以指出我正确的方向来解决这个问题吗?谢谢!

可以找到完整的日志HERE, as well as ConfigManager.h and ConfigManager.cpp

*我更愿意将其写在评论中,因为我没有 arduino,无法验证我的建议是否 100% 有用。但我不能将评论与 "my reputation" 一起使用 :)。所以如果我的回答没有帮助,请不要按 "minus button"... *

根据 that 看来您在使用 json 缓冲区时需要保留原始 json 字符串。

  1. Keep the JSON string in memory long enough

The library never make memory duplication. This has an important implication on string values, it means that the library will return pointer to chunks of the string.

For instance, let’s imagine that you parse ["hello","world"], like this:

char[] json = "[\"hello\",\"world\"]";

StaticJsonBuffer<32> buffer;

JsonArray& array = buffer.parseArray(json);

const char* first = array[0];

const char* second = array[1];

In that case, both first and second are pointers to the content of the original string json. So this will only work if json is still in memory.

因此,尝试使 std::unique_ptr buf 成为 class 成员(与 StaticJsonBuffer 相同)并检查其工作原理是有意义的。

顺便说一句,IMO std::vector 会更适合那里...而且我不确定 unique_ptr 是否正确删除数组。