define与enum的取舍

define与enum的取舍

事故现场

最近在项目中需要处理两个平台之间的通讯,开发环境如下:

  • 上位机环境:i.MX8QM (ARM64 Linux)
  • 上位机编译器:aarch-linux-gcc
  • 单片机环境:STM32F407VE
  • 单片机编译器:IAR 8.22.3
  • 通讯方式:i.MX8QM作为主机,STM32F407VE作为从机,通过SPI通讯。

两者在通讯时使用同一份通讯包结构体头文件,其中核心接头体如下

#define SPI_MSG_BUFF_LEN 132

enum SPI_CMD_INDEX {
  SPI_ERROR = 0,
  SPI_CONFIG_DATA,
  SPI_LOG,
  SPI_STOP,
  SPI_ACK
};

struct SpiMessage {
  enum SPI_CMD_INDEX Cmd;
  uint8_t Len;
  uint16_t Num;
  uint32_t HeadCrc;
  uint8_t Data[SPI_MSG_BUFF_LEN];
};

这里我人为的对数据做了对齐操作,按我的理解,我认为enum的数量没有超过255,一个字节的空间足够存放数据,所以长度应该是1字节,在IAR编译通过,并用逻辑分析仪测试,没有问题。输出的报文头的字节码为:<0x02, 0x23, 0x02, 0x00>。

从机完成后再在linux上实现驱动,但是出现了两个现象:

  • 发送一个定长报文的数据比预期的结构体长3个字节,
  • 报文头的字节码变成了<0x02, 0x00, 0x00, 0x00>,

我意识到enum长度在不同编译器的下应该是不同的(事实上这个主要和编译器的编译参数有关)。

解决方法

在struct中将enum SPI_CMD_INDEX替换为uint8_t,强制结构体中数据的字长。修改后代码如下:

struct SpiMessage {
  uint8_t Cmd;
  uint8_t Len;
  uint16_t Num;
  uint32_t HeadCrc;
  uint8_t Data[SPI_MSG_BUFF_LEN];

后面赋值的时候由于进行了变量类型转换,编译器会报警,可以将enum替换为#define:

#define  SPI_ERROR 			0
#define  SPI_CONFIG_DATA	1
#define  SPI_LOG			2
#define  SPI_STOP			3
#define  SPI_ACK			4

扩展

由于使用enum根据编译器参数的不同会导致编译出来的代码对结构体的理解不同,所以在编写与其他模块交互或者通讯类的代码时需要注意不能使用enum,这点可以参考linux ioctl编写时会用一个__IOC()的宏来定义交互的指令。

enum在模块内部调用的时候就显得非常有用,在函数传参、switch等关键词中可能大大降低代码错误的概率,并且在C++中对非enum定义的量是无法给enum定义的量赋值的,例如以下操作时非法的:

#define SPI_MSG_BUFF_LEN 132

enum SPI_CMD_INDEX {
  SPI_ERROR = 0,
  SPI_CONFIG_DATA,
  SPI_LOG,
  SPI_STOP,
  SPI_ACK
};

struct SpiMessage {
  enum SPI_CMD_INDEX Cmd;
  uint8_t Len;
  uint16_t Num;
  uint32_t HeadCrc;
  uint8_t Data[SPI_MSG_BUFF_LEN];
};

struct SpiMessage tmpMsg;

void main() {
  tmpMsg.Cmd = 1; // 代码非法,1不是enum SPI_CMD_INDEX定义的变量
  
  tmpMsg.Cmd = SPI_CONFIG_DATA; // 合法代码
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值