Bul*_*kin 13 c c++ struct arduino stm32
任务是通过I2C将数据从Arduino发送到STM32.
所以我使用C++在Arduino中定义了Struct和Enums:
enum PhaseCommands {
PHASE_COMMAND_TIMESYNC = 0x01,
PHASE_COMMAND_SETPOWER = 0x02,
PHASE_COMMAND_CALIBRATE = 0x03
};
enum PhaseTargets {
PHASE_CONTROLLER = 0x01,
// RESERVED = 0x02,
PHASE_LOAD1 = 0x03,
PHASE_LOAD2 = 0x04
};
struct saatProtoExec {
PhaseTargets target;
PhaseCommands commandName;
uint32_t commandBody;
} phaseCommand;
uint8_t phaseCommandBufferSize = sizeof(phaseCommand);
phaseCommand.target = PHASE_LOAD1;
phaseCommand.commandName = PHASE_COMMAND_SETPOWER;
phaseCommand.commandBody = (uint32_t)50;
Run Code Online (Sandbox Code Playgroud)
另一方面,我使用C得到了相同的定义:
typedef enum {
COMMAND_TIMESYNC = 0x01,
COMMAND_SETPOWER = 0x02,
COMMAND_CALIBRATE = 0x03
} MasterCommands;
typedef enum {
CONTROLLER = 0x01,
// RESERVED = 0x02,
LOAD1 = 0x03,
LOAD2 = 0x04
} Targets;
struct saatProtoExec {
Targets target;
MasterCommands commandName;
uint32_t commandBody;
} execCommand;
uint8_t execBufferSize = sizeof(execCommand);
execCommand.target = LOAD1;
execCommand.commandName = COMMAND_SETPOWER;
execCommand.commandBody = 50;
Run Code Online (Sandbox Code Playgroud)
然后我逐字节比较这个Structs:
=====================
BYTE | C++ | C
=====================
Byte 0 -> 0x3 -> 0x3
Byte 1 -> 0x0 -> 0x2
Byte 2 -> 0x2 -> 0x0
Byte 3 -> 0x0 -> 0x0
Byte 4 -> 0x32 -> 0x32
Byte 5 -> 0x0 -> 0x0
Byte 6 -> 0x0 -> 0x0
Byte 7 -> 0x0 -> 0x0
Run Code Online (Sandbox Code Playgroud)
那么为什么字节1和2不同呢?
unw*_*ind 24
这是一个非常糟糕的主意.
你永远不应该依赖于C的两个实现之间的结构的二进制表示,更不用说从C到C++了!
您应该执行一些正确的序列化/反序列化代码,以控制结构外部表示的字节级别.
也就是说,这可能是由于填充.你最终通过外部链接发送填充(这只是编译器添加的东西,以保持其主机CPU满意)是另一个迹象表明这种方法有多么破碎.
在C版本中很明显sizeof(Targets) == 1.看起来结构的第二个字段是2字节对齐的,所以你有一个填充字节,内容未定义.
现在,在C++中,sizeof(PhaseTargets)可能是1或2.如果它1(可能)一切都很好并且你有相同的填充空间,恰好有不同的垃圾值.如果是2......好吧,你的枚举值会有误!
初始化结构的简单方法是在变量的定义中.如果还没有值,只需添加一个0,所有结构将初始化为0.
struct saatProtoExec execCommand = {0};
Run Code Online (Sandbox Code Playgroud)
如果无法完成,则可以memset()在使用前将其归零.
一个可移植的替代方法是将结构的字段声明为适当大小的整数,并将这些enum类型用作常量集合.
struct saatProtoExec {
uint8_t target;
uint8_t commandName;
uint8_t padding[2];
uint32_t commandBody;
} execCommand;
Run Code Online (Sandbox Code Playgroud)