如何判断一段字符串的长度

描述

 

来源:公众号【鱼鹰谈单片机】

作者:鱼鹰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 可以在编译阶段就可以判断这个字符串的长度是否符合要求,多一个、少一个字符都不行。

这个坑你们遇到过吗?

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分