Является ли использование структур с виртуальным наследованием плохой идеей при чтении из EEPROM? (Ардуино)

Я столкнулся со странной проблемой, когда, если я загружаю свою структуру данных из EEPROM, она отбрасывает ее неправильно. Но если у меня есть как мои вызовы функций для функции, отвечающей за сохранение структуры данных, так и для функции, отвечающей за чтение структуры данных, она успешно передает данные в мою структуру.

Я немного поиграл с этой проблемой и заметил, что сохраненные данные и данные, считанные из EEPROM, всегда верны, если вы читаете их как uint8_t. Но по какой-то причине он не может привести данные в мою структуру данных (BareKeyboardKey2), когда функция сохранения не используется в программе, и мы только читаем данные из EEPROM.

Я считаю, что следующая структура вызывает проблему:

// testStruct.h

struct IKey2
{
    int pin;
};

struct BareKeyboardKey2 : virtual IKey2
{
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};

Пример вывода, когда я сначала вызываю SaveStruct, а затем LoadStruct. (Данные, которые я сохраняю в EEPROM, представляют собой BareKeyboardKey2(2, 4):

Чтение: 0x68 0x1 0x4 0x0 0x2 0x0
контакт: 2, код ключа: 4

как видите, BareKeyboardKey2 приводится правильно, но... Вот пример вывода, когда вызывается ТОЛЬКО LoadStruct (и те же данные из предыдущего примера хранятся в EEPROM):

Чтение: 0x68 0x1 0x4 0x0 0x2 0x0
pin: -18248, keycode: 4

Как вы можете видеть, данные, считанные из EEPROM (т.е. 0x68 0x1 0x4 0x0 0x2 0x0), одинаковы в обоих примерах, но в последнем примере не удается правильно преобразовать данные в BareKeyboardKey2 (pin: -18248, keycode: 4).

Я обнаружил, что если я изменяю структуру на следующую, она работает независимо от того, использую ли я последовательно SaveStruct и LoadStruct или только LoadStruct:

// testStruct.h
struct IKey2
{
};

struct BareKeyboardKey2 : virtual IKey2
{
    int pin;
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};

Я также обнаружил, что если я перемещу обе переменные в IKey2 вот так...:

struct IKey2
{
    int pin;
    int keyCode;
};

struct BareKeyboardKey2 : virtual IKey2
{
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};

... это приводит к тому, что программа неправильно приводит обе переменные. Пример вывода: pin: -18248, keycode: -18248

Что вызывает такое поведение и что я могу сделать, чтобы сделать его последовательным?


person HeroTeddy    schedule 06.09.2020    source источник


Ответы (1)


Я нашел решение своей проблемы. Я не уверен на 100%, что это правильно, но это моя теория...

При сохранении структур, отличных от POD, в виде байтов в EEPROM не сохраняется соединение между основной структурой и виртуальным объектом, подключенным к структуре. Таким образом, данные те же самые, но если вы заглянете в объект с помощью отладчика (в моем случае gdb), то увидите, что виртуальный указатель, который соединяет основную структуру и виртуальный объект, является недопустимым указателем. Хотя остальные данные, изначально присутствующие в основной структуре, остаются нетронутыми.

Итак, в моем случае, чтобы решить проблему, я преобразовал свою структуру в тип POD, удалив виртуальное наследование из моей структуры. Вместо этого я использовал связь «Имеет отношение», и до сих пор мои данные правильно читались из EEPROM, независимо от различных случаев, использованных выше.

person HeroTeddy    schedule 15.09.2020