是否可以对嵌入式软件的C宏进行单元测试?
我是如何为嵌入式软件测试一些特定的 C 宏的。
例如,如果我有以下宏:
/*
Set a pin as an input
port (B,C, D or E)
pin - pin to set (0-7)
*/
#define _SET_INPUT_PIN(port,pin) DDR ## port &= ~(1<<pin)
#define SET_INPUT_PIN(...) _SET_INPUT_PIN(__VA_ARGS__)
我想用两个端口测试它,一个存在(LED_OK)另一个不存在(LED_FAIL):
#define LED_OK D,3
#define LED_FAIL D,8
当我尝试测试它时,LED_OK 和 LED_FAIL 都可以正常工作,但某种警告/失败应该提醒 LED_FAIL 不存在,因为 PORTD 只定义了引脚 0 到 7。
那么,当我通过LED 时,如何检查“ pin ”是否在范围内?
回答
这太晦涩了。一般来说,我强烈建议不要隐藏超琐碎的东西,比如设置/清除抽象层后面的引脚。
相反,您应该编写如下内容:
#define LED_DDR DDRD
#define LED_PORT PORTD
#define LED_PIN (1u << 3)
LED_DDR |= LED_PIN; // set pin to output
LED_PORT |= LED_PIN; // set pin to 1
LED_PORT &= ~LED_PIN; // set pin to 0
LED_PORT &= (uint8_t)~LED_PIN; // set pin to 0 with pedantic type safety (MISRA-C etc)
LED_PORT ^= LED_PIN; // toggle pin
您无法真正编写更清晰的代码,因此超出此范围的任何抽象层都注定要失败。它不会增加清晰度,但可能会增加错误。从人们试图这样做的 SO/EE 站点上的数千个粗略尝试中可以看出。或者从硅供应商的膨胀软件库中看到。
因此,适当的测试不会测试晦涩的宏,SET_INPUT_PIN而是质疑它的存在。测试的名称是代码审查。这也会指出以下问题:
- 绝对没有必要把它变成一个可变参数宏,因为它应该只接受 2 个参数——不多也不少。这不过是纯粹的混淆。
- 此宏不提供类型安全。调用者实际上可以将任何内容传递给它,并且有很大的机会静默传递编译。
- 以下划线开头,后跟大写字母的标识符是为库保留的。所以不要命名宏
_S等,它可能会与编译器库发生冲突。 - 宏写得很天真。那里的平均编码标准将
( (DDR ## port) &= ~(1 <<(pin)) )在宏参数和最终表达式周围强制使用括号。 - 该宏使用有
1符号整数常量,一旦我们在可能具有 16 位int. 然后我们会到处都是未定义的行为错误。应该是1u。 - 有隐式提升,所以宏实际上返回一个 16 位负值
int。这是无益和危险的。