來(lái)源:公眾號(hào)【魚鷹談單片機(jī)】
作者:魚鷹Osprey
ID :emOsprey
這周課上介紹斷言實(shí)現(xiàn)的時(shí)候,莫名其妙被斷言的真真假假搞暈了。
起因是看到一段關(guān)于判斷一段字符串的長(zhǎng)度,使用了 ASSERT 方式,原文大概是這樣寫的:
#define AES256_KEY "0123456789ABCDEF0123456789ABCDEF" /* 必須等于 32 字節(jié) */ #define AES256_IV "0123456789ABCDEF" /* 必須等于 16 字節(jié) */ extern void Assert_Failed(uint8_t *func, uint32_t line); #define ASSERT(expr) ((expr) ? (void)0U : Assert_Failed((uint8_t *)__func__, __LINE__)) voidfunc() { ASSERT(sizeof(AES256_KEY) != 32); ASSERT(sizeof(AES256_IV) != 16); }
一開(kāi)始總以為這種寫法沒(méi)問(wèn)題,畢竟這么簡(jiǎn)單,模擬調(diào)試的時(shí)候確實(shí)也不會(huì)報(bào)錯(cuò)(打開(kāi)了斷言情況下)。
為了課上測(cè)試一下靜態(tài)編譯報(bào)錯(cuò)的效果,卻發(fā)現(xiàn)始終有些問(wèn)題,不該報(bào)錯(cuò)的時(shí)候報(bào)錯(cuò)了。
#define STATIC_ASSERT(...) extern char (*_do_assert(void)) [sizeof(char[1 - 2*!(__VA_ARGS__)])]
為了方便,魚鷹直接用 MDK 測(cè)試了 sizeof 字符串的結(jié)果,發(fā)現(xiàn)確實(shí)也是16(0x10)

然后我就困在了這兩個(gè)前提上,STATIC_ASSERT 報(bào)錯(cuò)始終有問(wèn)題。
#define AES256_KEY "0123456789ABCDEF0123456789ABCDEF" /* 必須等于 32 字節(jié) */
#define AES256_IV "0123456789ABCDEF" /* 必須等于 16 字節(jié) */
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);
}

調(diào)試的時(shí)候,STATIC_ASSERT 報(bào)錯(cuò),但是 ASSERT不報(bào)錯(cuò)。
這讓魚鷹百思不得其解,一開(kāi)始以為兩個(gè)宏邏輯相反,不都是邏輯值為假時(shí)報(bào)錯(cuò)。
但是通過(guò)分析宏發(fā)現(xiàn),都是假的時(shí)候報(bào)錯(cuò)。
那肯定哪里分析有問(wèn)題了。
因?yàn)榫幾g器如果能得到結(jié)果為真,ASSERT可能無(wú)法形成代碼,即為空(void)0U。
因此魚鷹使用了一個(gè)變量作為中間值,強(qiáng)行讓編譯器生成斷言相關(guān)的代碼,才算是發(fā)現(xiàn)了問(wèn)題。
void func()
{
uint32_tsize = sizeof(AES256_IV);
ASSERT(sizeof(AES256_KEY) != 32);
ASSERT(size!=16);
STATIC_ASSERT(sizeof(AES256_IV) != 16);
}
這個(gè)size 的值竟然是 17,而不是 16,難怪初始代碼不報(bào)錯(cuò),17 != 16,當(dāng)然為真,當(dāng)然不報(bào)錯(cuò)。
但寫代碼的人是希望這個(gè)字符串的長(zhǎng)度為始終是16(不包含null的情況下),而明顯代碼中使用sizeof 時(shí)計(jì)算了 null 的長(zhǎng)度。
所以代碼應(yīng)該這樣寫才對(duì):
void func()
{
ASSERT(sizeof(AES256_KEY)==32);
ASSERT(sizeof(AES256_IV)==16);
STATIC_ASSERT(sizeof(AES256_IV)==16);
}
但是又因?yàn)榇a的sizeof 會(huì)計(jì)算null,因此需要去除這個(gè)數(shù):
void func()
{
ASSERT(sizeof(AES256_KEY) - 1==32);
ASSERT(sizeof(AES256_IV) - 1==16);
STATIC_ASSERT(sizeof(AES256_IV) - 1==16);
}

這樣 STATIC_ASSERT 可以在編譯階段就可以判斷這個(gè)字符串的長(zhǎng)度是否符合要求,多一個(gè)、少一個(gè)字符都不行。
這個(gè)坑你們遇到過(guò)嗎?
-
字符串
+關(guān)注
關(guān)注
1文章
594瀏覽量
22963 -
編譯器
+關(guān)注
關(guān)注
1文章
1665瀏覽量
50956 -
編譯
+關(guān)注
關(guān)注
0文章
682瀏覽量
34863
原文標(biāo)題:被斷言罷了一道
文章出處:【微信號(hào):emOsprey,微信公眾號(hào):魚鷹談單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄

如何判斷一段字符串的長(zhǎng)度
評(píng)論