sscanf()十六进制成一个int与无符号字符的数组

ubt*_*tac 2 c types scanf strtol

我正在将一个mac地址的字符串表示转换为一个UINT8定义为的数组unsigned char.我好奇为什么当我读入常规32位s 的数组时读入s和实际值sscanf()的数组时会读取全0 .它几乎就像是砍掉了int的错误结束的8位.UINT8int

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
Run Code Online (Sandbox Code Playgroud)

更新:%hhx将适用于C99及以上,但我有一个旧的代码库,所以我最终得到strtoul():

char *str = strMac;
int i = 0;
for(i = 0; i < 6; i++, str+=3) {
    uMAC[i] = strtoul(str, NULL, 16);
}
Run Code Online (Sandbox Code Playgroud)

Sou*_*osh 5

TL; DR - 由于参数类型不匹配,第一个片段会调用UB.


详细说明,引用%x格式说明符的参数类型的要求,从C11标准的章节§7.21.6.2,fscanf()函数,(强调我的)

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] );
Run Code Online (Sandbox Code Playgroud)

在你的代码中,你提供了错误的参数类型%x.根据标准,再次,

[...].除非由a指示赋值抑制,否则*转换的结果将放在由尚未收到转换结果的format参数后面的第一个参数指向的对象中.如果此对象没有适当的类型,或者无法在对象中表示转换结果,则行为未定义.

因此,提供错误类型作为参数是调用 未定义的行为.


解:

为了表示你要提供一个(符号或无符号)char输入参数,你需要使用前面带格式说明hh长度修改,如%hhxscanf()家人.