来源:公众号【鱼鹰谈单片机】
作者:鱼鹰Osprey
ID :emOsprey
这周课上介绍断言实现的时候,莫名其妙被断言的真真假假搞晕了。
起因是看到一段关于判断一段字符串的长度,使用了 ASSERT 方式,原文大概是这样写的:
#define AES256_KEY "0123456789ABCDEF0123456789ABCDEF" /* 必须等于 32 字节 */ #define AES256_IV "0123456789ABCDEF" /* 必须等于 16 字节 */ extern void Assert_Failed(uint8_t *func, uint32_t line); #define ASSERT(expr) ((expr) ? (void)0U : Assert_Failed((uint8_t *)__func__, __LINE__)) void func() { ASSERT(sizeof(AES256_KEY) != 32); ASSERT(sizeof(AES256_IV) != 16); }
一开始总以为这种写法没问题,毕竟这么简单,模拟调试的时候确实也不会报错(打开了断言情况下)。
为了课上测试一下静态编译报错的效果,却发现始终有些问题,不该报错的时候报错了。
#define STATIC_ASSERT(...) extern char (*_do_assert(void)) [sizeof(char[1 - 2*!(__VA_ARGS__)])]
为了方便,鱼鹰直接用 MDK 测试了 sizeof 字符串的结果,发现确实也是 16(0x10)
然后我就困在了这两个前提上,STATIC_ASSERT 报错始终有问题。
#define AES256_KEY "0123456789ABCDEF0123456789ABCDEF" /* 必须等于 32 字节 */ #define AES256_IV "0123456789ABCDEF" /* 必须等于 16 字节 */ extern void Assert_Failed(uint8_t *func, uint32_t line); #define ASSERT(expr) ((expr) ? (void)0U : Assert_Failed((uint8_t *)__func__, __LINE__)) #define STATIC_ASSERT(...) extern char (*_do_assert(void)) [sizeof(char[1 - 2*!(__VA_ARGS__)])] void func() { ASSERT(sizeof(AES256_KEY) != 32); ASSERT(sizeof(AES256_IV) != 16); STATIC_ASSERT(sizeof(AES256_IV) != 16); }
调试的时候,STATIC_ASSERT 报错,但是 ASSERT 不报错。
这让鱼鹰百思不得其解,一开始以为两个宏逻辑相反,不都是逻辑值为假时报错。
但是通过分析宏发现,都是假的时候报错。
那肯定哪里分析有问题了。
因为编译器如果能得到结果为真,ASSERT 可能无法形成代码,即为空(void)0U。
因此鱼鹰使用了一个变量作为中间值,强行让编译器生成断言相关的代码,才算是发现了问题。
void func() { uint32_t size = sizeof(AES256_IV); ASSERT(sizeof(AES256_KEY) != 32); ASSERT(size != 16); STATIC_ASSERT(sizeof(AES256_IV) != 16); }
这个size 的值竟然是 17,而不是 16,难怪初始代码不报错,17 != 16,当然为真,当然不报错。
但写代码的人是希望这个字符串的长度为始终是16(不包含null的情况下),而明显代码中使用sizeof 时计算了 null 的长度。
所以代码应该这样写才对:
void func() { ASSERT(sizeof(AES256_KEY) == 32); ASSERT(sizeof(AES256_IV) == 16); STATIC_ASSERT(sizeof(AES256_IV) == 16); }
但是又因为代码的sizeof 会计算null,因此需要去除这个数:
void func() { ASSERT(sizeof(AES256_KEY) - 1 == 32); ASSERT(sizeof(AES256_IV) - 1 == 16); STATIC_ASSERT(sizeof(AES256_IV) - 1 == 16); }
这样 STATIC_ASSERT 可以在编译阶段就可以判断这个字符串的长度是否符合要求,多一个、少一个字符都不行。
这个坑你们遇到过吗?
全部0条评论
快来发表一下你的评论吧 !