本文介绍了缓冲区被覆盖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我对c / c ++之类的本地语言没有太多经验,我面临一个奇怪的问题,这使我发疯。因此,我使用的是Wemos D1 mini(ESP8266),该类使用名为 ConfigManager 的类从eeprom中读取配置文件。配置文件的格式为json,因此我正在使用来解析内容。我已经在头文件中声明了 StaticJsonBuffer 并指向 JsonObject 的指针,就像您在代码示例中看到的那样: / p>

I have not that much experience with native languages like c/c++ and I'm facing a strange issue, which drives me crazy. So I'm using an Wemos D1 mini (ESP8266) which uses a class calles ConfigManager to read a configuration file from eeprom. The config file is formatted as json, so I'm using ArduinoJson to parse the content. I have declared a StaticJsonBuffer and pointer to a JsonObject in the header, like you can see in the code example:

//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

When the function read_from_eeprom is invoked, it opens the file and invokes the functionread_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}

So what I noticed is that the file content is fine. E.g. {"version":"0.2","led_count":"64"}.

然后解析json,成功并记录json对象,该对象又是 { version: 0.2, led_count : 64}

Then the json is parsed, which succeeds and logs the json object, which is again {"version":"0.2","led_count":"64"}.

此后,函数返回,并调用 check_success ,这再次将json对象的内容打印到日志中,但是这一次似乎已经覆盖了JsonBuffer,这导致json对象被破坏。这次记录的内容为 {v␂: 0.2, led_count: 64} (随着源代码的更改,一些奇怪的独角兽字符也会更改) )。我想弄清楚现在已经发生了很多小时,但是我被困住了。有人可以指出正确的方向来解决这个问题吗?谢谢!

Afterwards the function returns, and calls check_success, which again prints the content of the json object to the log, but this time it seems that something has overwritten the JsonBuffer, which causes the json object to be corrupted. This time the logged content is {"v␂":"0.2","led_count":"64"} (with some strange unicorn characters that change as the source code changes). I'm trying to figure out whats going on for many hours now, but I'm stuck. Can someone please point me in the right direction to solve this problem? Thank you!

完整的日志可以找到,以及和

The full Log can be found HERE, as well as ConfigManager.h and ConfigManager.cpp

推荐答案

*我更喜欢在注释中写出来,因为我没有arduino并且无法验证我的建议是否100%有用。但是我不能使用带有我的声誉的评论:)。因此,如果我的回答没有帮助,请不要按减号按钮 ... *

*I'd prefer write that in comments, because I don't have arduino and can't verify that my advice 100% helpful. But I can't use comments with "my reputation" :). So please don't press "minus button" if my answer didn't help... *

根据似乎您在使用json缓冲区时需要保留原始的json字符串。 / p>

According to that it seems you need to keep original json string while you using json buffer.


  1. 将JSON字符串在内存中保留足够长的时间

该库从不进行内存复制。这对字符串
值有重要意义,这意味着库将返回指向
字符串块的指针。

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.

例如,让我们想象您解析了[ hello, world],就像
这样:

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

char [] json = [\ hello\ ,\世界\];

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

StaticJsonBuffer< 32>缓冲区;

StaticJsonBuffer<32> buffer;

JsonArray& array = buffer.parseArray(json);

JsonArray& array = buffer.parseArray(json);

const char * first = array [0];

const char* first = array[0];

const char * second = array [1];

const char* second = array[1];

在这种
情况下,第一和第二个都是指向
原始字符串json内容的指针。因此,仅当json仍在
内存中时,此方法才起作用。

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是一个类成员(与StaticJsonBuffer相同),并检查其工作原理。

So, it make sense try make std::unique_ptr buf a class member (same as StaticJsonBuffer) and check how it works.

BTW,IMO std :: vector在那里更适合...而且我不是确保unique_ptr正确删除了数组。

BTW, IMO std::vector will be more suitable there... And I'm not sure that unique_ptr deletes arrays properly.

这篇关于缓冲区被覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 02:35