【问题标题】:sscanf() hex ints into an array of ints vs. unsigned charssscanf() 将十六进制整数转换为整数数组与无符号字符
【发布时间】:2015-10-27 04:38:03
【问题描述】:

我正在将 mac 地址的字符串表示形式转换为定义为 unsigned charUINT8s 数组。我很好奇为什么当我读入UINT8s 的数组时sscanf() 会读取全0,而当我读入常规的32 位ints 的数组时会读取实际值。它几乎就像是在切掉 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);
}

【问题讨论】:

  • 您在此处调用了未定义的行为,因此提供的任何解释都不完整。
  • char *strMac = "11:22:33:AA:BB:CC";?
  • 不是这里的主要问题,但在sscanf( (const char*) strMac,... 中不需要(const char*)

标签: c types scanf strtol


【解决方案1】:

TL;DR - 由于参数类型不匹配,第一个 sn-p 调用 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] );

在您的代码中,您为 %x 提供了错误类型的参数。再次按照标准,

[...]。除非 * 指示分配抑制,否则 转换结果放置在格式参数后面的第一个参数所指向的对象中,该参数尚未收到转换结果。如果此对象没有适当的类型,或者转换的结果无法在对象中表示,则行为未定义。

因此,提供错误类型作为参数是在调用undefined behaviour


解决方案:

要表明您将提供一个(有符号或无符号)char 类型参数,您需要使用带有 hh 长度修饰符前缀的格式说明符,例如 %hhxscanf() 系列。

【讨论】:

  • @EOF 现在怎么样? :-)
  • 我无法控制我的构建环境(而且它被混淆了),所以我不知道我们使用什么版本的 C。 %hhx 静默失败:我没有收到编译器错误,但它不起作用。但我不明白 sscanf(strMac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &uMAC[0], &uMAC[1], &uMAC[2], &uMAC[3 ], &uMAC[4], &uMAC[5] ) 如果 hh 不是有效的格式说明符,则为有效语句。
  • @ubtac %hhx 于 1999 年添加。如果您的环境较旧,则必须读取 unsigned int 对象,然后将结果一一复制到您的 char 数组中。
  • @ubtac 另一种选择是不使用 scanf
  • @MattMcNabb 这就是我最终的结果,只是好奇%hhx 在(大概)ANSI C 中是如何有效的。
猜你喜欢
  • 1970-01-01
  • 2015-12-02
  • 1970-01-01
  • 2019-10-31
  • 1970-01-01
  • 2021-11-05
  • 2019-05-03
相关资源
最近更新 更多