我正在将mac地址的字符串表示转换为UINT8
的数组,定义为unsigned char
。我很好奇当我读入常规32位sscanf()
的数组时,当我读入UINT8
s数组和实际值时,int
将读取所有0。它几乎就像是砍掉了int的错误结束的8位。
char *strMAC = "11:22:33:AA:BB:CC";
typedef unsigned char UINT8;
UINT8 uMAC[6];
int iMAC[6];
sscanf( (const char*) strMac,
"%x:%x:%x:%x:%x:%x",
&uMAC[0], &uMAC[1], &uMAC[2], &uMAC[3], &uMAC[4], &uMAC[5] );
printf( "%x:%x:%x:%x:%x:%x",
uMAC[0], uMAC[1], uMAC[2], uMAC[3], uMAC[4], uMAC[5] );
// output: 0:0:0:0:0:0
sscanf( (const char*) strMac,
"%x:%x:%x:%x:%x:%x",
&iMAC[0], &iMAC[1], &iMAC[2], &iMAC[3], &iMAC[4], &iMAC[5] );
printf( "%x:%x:%x:%x:%x:%x",
iMAC[0], iMAC[1], iMAC[2], iMAC[3], iMAC[4], iMAC[5] );
// output: 11:22:33:AA:BB:CC
更新:%hhx
适用于C99及更高版本,但我有一个旧的代码库,所以我最终选择strtoul()
:
char *str = strMac;
int i = 0;
for(i = 0; i < 6; i++, str+=3) {
uMAC[i] = strtoul(str, NULL, 16);
}
答案 0 :(得分:5)
TL; DR - 由于参数类型不匹配,第一个片段会调用UB。
详细说明,引用%x
格式说明符的参数类型要求,来自C11
标准,章节§7.21.6.2,fscanf()
函数,(强调我的 EM>)
x
匹配一个可选的带符号十六进制整数,其格式与strtoul()
函数的主题序列的预期相同,其基值参数值为16。 相应的参数应该是指向无符号整数的指针。
所以,在使用
时 sscanf( (const char*) strMac,
"%x:%x:%x:%x:%x:%x",
&uMAC[0], &uMAC[1], &uMAC[2], &uMAC[3], &uMAC[4], &uMAC[5] );
在您的代码中,您为%x
提供了错误的参数类型。根据标准,再次,
[...]。除非
*
表示分配抑制,否则 转换结果放在由尚未收到转换结果的format参数后面的第一个参数指向的对象中。如果此对象没有适当的类型,或者无法在对象中表示转换结果,则行为未定义。
因此,提供错误的类型作为参数正在调用undefined behaviour。
<强>解决方案:强>
要表明您要提供(有符号或无符号)char
类型参数,您需要使用前缀为hh
长度修饰符的格式说明符,例如%hhx
与scanf()
家人合作。