奇怪的printf()行为

我附上这个问题的代码应该得到设备的mac地址并打印出来。 当我将结构ifreq中的数据复制到uint8_t数组时,它可以工作,但是当我没有,我得到奇怪的结果。 查看第二行和输出的第二个字节。

#include  #include  #include  #include  #include  #include  #include  #include  int main() { uint8_t tab[6]; int i; struct ifreq one; int sd = socket(AF_PACKET, SOCK_RAW, 0); memset(&one, 0, sizeof(struct ifreq)); strcpy(one.ifr_name, "eth0"); int v = ioctl(sd, SIOCGIFHWADDR, &one); memcpy(tab, one.ifr_hwaddr.sa_data, sizeof(uint8_t) * 6); for(i=0;i<6;i++) printf("%02x:", tab[i]); printf("\n"); for(i=0;i<6;i++) printf("%02x:", one.ifr_hwaddr.sa_data[i]); printf("\n"); } 

OUTPUT:

74:86:7A:0A:2C:6D:

74:ffffff86:7A:0A:2C:6D:

你问为什么第二个字节打印为ffffff86而不是86 ? 这是因为它已经过符号扩展。 one.ifr_hwaddr.sa_data[i]数组声明为有符号字符数组,但tab []数组是无符号的。

printf的args都被提升为int。 无符号字符0x86被提升为0x00000086,但是当假定相同的值被签名时,它将被提升为0xFFFFFF86。

整数促销再次罢工!

由于转换说明符"x"使用两行printf一个unsigned int

要打印signedunsigend int的一半(假设为32位整数),请使用长度修改器"h"两次:

 printf("%02hhx:", one.ifr_hwaddr.sa_data[i]); 

在一种情况下,您可以指定促销的方式。 在第二种情况下,你没有。 您需要促销未签名。 因此,不指定它是如何发生的,会导致问题。

如果字节是0x8f,则需要提升该值,就好像该类型是无符号的一样。 否则,保留该值需要保留符号位。

促销使价值保持不变。 因此,当它们被提升时,如何将原始位解释为值,这会产生巨大的差异。

我怀疑,one.ifr_hwaddr.sa_data是字符数组。在这种情况下,char表示签名字符。

因此,当通过printf的变量参数列表传递时,它被提升为int,printf将其打印为unsigned int(“x”说明符)

当从char提升为int时,编译器的目标是保留其值 – 而不是其二进制表示。

0x86是134作为十进制,被视为unsigned char和-122,被视为signed char。

134 as unsigned int表示为0x68 -122,因为int表示为0xffffff86(-1表示int为0xffffffff)

因此,打印0xffffff86。 在这种情况下(打印二进制为hex)我使用%02hhx printf说明符%hhx告诉printf将其视为无符号字符 – 仅有1个字节。