从 EEPROM 读取时,使用具有虚拟继承的结构是个坏主意吗? (阿杜伊诺)
Is using structs with virtual inheritance a bad idea when reading from EEPROM? (Arduino)
我 运行 遇到了一个奇怪的问题,如果我从 EEPROM 加载我的数据结构,它会错误地转换它。但是,如果我同时调用了负责保存数据结构的函数和负责读取数据结构的函数,它就会成功地将数据转换为我的结构。
我稍微解决了这个问题,我注意到保存的数据和从 EEPROM 读取的数据总是正确的,如果你把它读成 uint8_t
。但是由于某些原因,当程序中没有使用保存功能并且我们只从 EEPROM 读取数据时,它无法将数据转换为我的数据结构(BareKeyboardKey2
)。
以下结构是我认为导致问题的原因:
// 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)
:
Reading: 0x68 0x1 0x4 0x0 0x2 0x0
pin: 2, keycode: 4
如您所见,它正确地投射了 BareKeyboardKey2
,但是...
这是仅调用 LoadStruct 时的 示例输出(并且来自上一个示例的相同数据存储在 EEPROM 中):
Reading: 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 中...:[=25=]
struct IKey2
{
int pin;
int keyCode;
};
struct BareKeyboardKey2 : virtual IKey2
{
BareKeyboardKey2() {}
BareKeyboardKey2(int _pin, int _keyCode)
{
pin = _pin;
keyCode = _keyCode;
}
};
... 这会导致程序错误地转换两个变量。示例输出:pin: -18248, keycode: -18248
是什么导致了这种行为,我该怎么做才能使其保持一致?
我找到了解决问题的方法。我不是 100% 确定它是正确的,但这是我的理论...
当将 non-POD 结构作为字节保存到 EEPROM 时,它不会保存主结构和连接到该结构的虚拟对象之间的连接。因此,数据是相同的,但是如果您使用调试器(在我的例子中是 gdb)查看对象,您将看到连接主结构和虚拟对象的虚拟指针是一个无效指针。尽管如此,最初存在于主结构中的其余数据仍然完好无损。
所以在我的例子中,为了解决这个问题,我通过从我的结构中删除虚拟继承将我的结构转换为 POD 类型。相反,我使用了“有一个”关系,到目前为止,无论上面使用的不同情况如何,我的数据都可以从 EEPROM 中正确读取。
我 运行 遇到了一个奇怪的问题,如果我从 EEPROM 加载我的数据结构,它会错误地转换它。但是,如果我同时调用了负责保存数据结构的函数和负责读取数据结构的函数,它就会成功地将数据转换为我的结构。
我稍微解决了这个问题,我注意到保存的数据和从 EEPROM 读取的数据总是正确的,如果你把它读成 uint8_t
。但是由于某些原因,当程序中没有使用保存功能并且我们只从 EEPROM 读取数据时,它无法将数据转换为我的数据结构(BareKeyboardKey2
)。
以下结构是我认为导致问题的原因:
// 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)
:
Reading: 0x68 0x1 0x4 0x0 0x2 0x0
pin: 2, keycode: 4
如您所见,它正确地投射了 BareKeyboardKey2
,但是...
这是仅调用 LoadStruct 时的 示例输出(并且来自上一个示例的相同数据存储在 EEPROM 中):
Reading: 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 中...:[=25=]
struct IKey2
{
int pin;
int keyCode;
};
struct BareKeyboardKey2 : virtual IKey2
{
BareKeyboardKey2() {}
BareKeyboardKey2(int _pin, int _keyCode)
{
pin = _pin;
keyCode = _keyCode;
}
};
... 这会导致程序错误地转换两个变量。示例输出:pin: -18248, keycode: -18248
是什么导致了这种行为,我该怎么做才能使其保持一致?
我找到了解决问题的方法。我不是 100% 确定它是正确的,但这是我的理论...
当将 non-POD 结构作为字节保存到 EEPROM 时,它不会保存主结构和连接到该结构的虚拟对象之间的连接。因此,数据是相同的,但是如果您使用调试器(在我的例子中是 gdb)查看对象,您将看到连接主结构和虚拟对象的虚拟指针是一个无效指针。尽管如此,最初存在于主结构中的其余数据仍然完好无损。
所以在我的例子中,为了解决这个问题,我通过从我的结构中删除虚拟继承将我的结构转换为 POD 类型。相反,我使用了“有一个”关系,到目前为止,无论上面使用的不同情况如何,我的数据都可以从 EEPROM 中正确读取。