2019-06-15 14:32:11 -07:00
|
|
|
/*
|
|
|
|
* test_cpp_memory_layout.cpp
|
|
|
|
*
|
|
|
|
* Jun 15, 2019
|
2020-01-07 21:02:40 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2019-06-15 14:32:11 -07:00
|
|
|
*/
|
|
|
|
|
2021-08-03 19:05:01 -07:00
|
|
|
#include "pch.h"
|
2019-06-15 14:32:11 -07:00
|
|
|
|
|
|
|
// in C++ struct is pretty much a class just fields are public by default
|
|
|
|
struct TestParent {
|
|
|
|
int field0 = 540;
|
|
|
|
float field1 = 333.33;
|
|
|
|
};
|
|
|
|
|
|
|
|
class TestPlainChild: public TestParent {
|
|
|
|
public:
|
|
|
|
float getSum();
|
|
|
|
};
|
|
|
|
|
|
|
|
class TestPlainChildExtraFields: public TestParent {
|
|
|
|
public:
|
|
|
|
float field3 = 35555;
|
|
|
|
float field4 = 45555;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
float TestPlainChild::getSum() {
|
|
|
|
return field0 + field1;
|
|
|
|
}
|
|
|
|
|
|
|
|
class TestChildWithVirtual: public TestParent {
|
|
|
|
public:
|
|
|
|
virtual float getSumVirtual() {
|
|
|
|
return field0 + field1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-02-02 13:36:35 -08:00
|
|
|
TEST(CppMemoryLayout, PlainStruct) {
|
2019-06-15 14:32:11 -07:00
|
|
|
TestPlainChild c;
|
|
|
|
// validate field initializers just for fun
|
|
|
|
ASSERT_EQ(540, c.field0);
|
|
|
|
ASSERT_NEAR(333.33, c.field1, EPS4D);
|
|
|
|
|
|
|
|
ASSERT_EQ(sizeof(c), sizeof(TestParent));
|
|
|
|
|
|
|
|
int destimationInt = 1;
|
|
|
|
// no virtual table since nothing virtual on TestPlainChild
|
|
|
|
memcpy(&destimationInt, &c, 4);
|
|
|
|
ASSERT_EQ(540, destimationInt);
|
|
|
|
|
2020-12-04 21:22:10 -08:00
|
|
|
ASSERT_EQ((uintptr_t)&c.field0, (uintptr_t)&c);
|
2019-06-15 14:32:11 -07:00
|
|
|
}
|
|
|
|
|
2019-08-25 14:38:08 -07:00
|
|
|
static int valueWePointAt;
|
|
|
|
|
2022-02-02 13:36:35 -08:00
|
|
|
TEST(CppMemoryLayout, VirtualStruct) {
|
2019-06-15 14:32:11 -07:00
|
|
|
TestChildWithVirtual c;
|
|
|
|
|
2019-08-25 14:38:08 -07:00
|
|
|
// '4' in case of 32 bit target
|
|
|
|
// '8' in case of 64 bit target
|
2022-02-02 13:36:35 -08:00
|
|
|
int MAGIC_VTABLE_SIZE = sizeof(void*);
|
2019-06-15 14:32:11 -07:00
|
|
|
|
|
|
|
// validate field initializers just for fun
|
|
|
|
ASSERT_EQ(540, c.field0);
|
|
|
|
ASSERT_NEAR(333.33, c.field1, EPS4D);
|
|
|
|
|
|
|
|
ASSERT_EQ(sizeof(c), sizeof(TestParent) + MAGIC_VTABLE_SIZE);
|
|
|
|
|
|
|
|
|
|
|
|
int destimationInt = 1;
|
|
|
|
memcpy(&destimationInt, &c, 4);
|
|
|
|
ASSERT_NE(540, destimationInt);
|
|
|
|
|
2019-06-17 07:22:43 -07:00
|
|
|
// static_cast is smart to skip the vtable, we like static_cast
|
|
|
|
TestParent *parent = static_cast<TestParent*>(&c);
|
2020-12-04 21:22:10 -08:00
|
|
|
ASSERT_EQ((uintptr_t)&c.field0, (uintptr_t)parent);
|
2019-06-17 07:22:43 -07:00
|
|
|
|
2020-12-04 21:22:10 -08:00
|
|
|
ASSERT_EQ(MAGIC_VTABLE_SIZE, (uintptr_t)&c.field0 - (uintptr_t)&c);
|
2019-06-17 07:22:43 -07:00
|
|
|
|
|
|
|
|
2019-06-15 14:32:11 -07:00
|
|
|
}
|
|
|
|
|
2022-02-02 13:36:35 -08:00
|
|
|
TEST(CppMemoryLayout, PlainExtraFieldsStruct) {
|
2019-06-15 14:32:11 -07:00
|
|
|
TestPlainChildExtraFields c;
|
|
|
|
|
|
|
|
ASSERT_EQ(sizeof(c), sizeof(TestParent) + 8);
|
|
|
|
|
|
|
|
int destimationInt = 1;
|
|
|
|
// parent fields go first
|
|
|
|
memcpy(&destimationInt, &c, 4);
|
|
|
|
ASSERT_EQ(540, destimationInt);
|
2020-12-04 21:22:10 -08:00
|
|
|
ASSERT_EQ(0, (uintptr_t)&c.field0 - (uintptr_t)&c);
|
2019-06-15 14:32:11 -07:00
|
|
|
}
|
2022-02-02 13:36:35 -08:00
|
|
|
|
|
|
|
TEST(CppMemoryLayout, structSize) {
|
2022-04-29 16:35:31 -07:00
|
|
|
ASSERT_EQ(1, sizeof(adc_channel_e)) << "adc_channel_e enum size";
|
|
|
|
ASSERT_EQ(1, sizeof(pin_input_mode_e)) << "pin_input_mode_e enum size";
|
|
|
|
ASSERT_EQ(1, sizeof(pin_output_mode_e)) << "pin_output_mode_e enum size";
|
|
|
|
ASSERT_EQ(2, sizeof(brain_pin_e)) << "brain_pin_e enum size";
|
2022-05-01 05:48:54 -07:00
|
|
|
ASSERT_EQ(12, sizeof(air_pressure_sensor_config_s));
|
2022-02-02 13:36:35 -08:00
|
|
|
ASSERT_EQ(TOTAL_CONFIG_SIZE, sizeof(persistent_config_s));
|
|
|
|
}
|