奇怪的printf()行为

时间:2014-03-27 17:19:59

标签: c linux sockets

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

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <net/ethernet.h>
#include <sys/types.h>
#include <stdint.h>

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");
}

输出:

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

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

4 个答案:

答案 0 :(得分:4)

您是否在问为什么第二个字节打印为ffffff86而不是86?这是因为它已被签名延长。 one.ifr_hwaddr.sa_data[i]数组被声明为有符号字符数组,但是tab []数组是无符号的。

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

答案 1 :(得分:1)

整体推广再次爆发!

由于转化说明符"x"同时使用了printf行和unsigned int

要打印signedunsigend int的一半(假设为32位整数),请使用length modifer "h"两次:

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

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

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

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

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

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

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

因此,打印0xffffff86。 在这种情况下(打印二进制为十六进制)我使用%02hhx printf说明符 %hhx告诉printf将其视为unsigned char - 只有1个字节。