Comportement étrange de printf ()

Le code que j’ai joint à cette question est censé obtenir l’adresse MAC du périphérique et l’imprimer. Cela fonctionne lorsque je copie des données de la structure ifreq dans le tableau de uint8_t, mais lorsque je ne le fais pas, j’obtiens des résultats étranges. Regardez la deuxième ligne et le deuxième octet de la sortie.

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

SORTIE:

74: 86: 7a: 0a: 2c: 6d:

74: ffffff86: 7a: 0a: 2c: 6d:

Voulez-vous savoir pourquoi le deuxième octet ffffff86 au lieu de 86 ? C’est parce qu’il a été étendu. Le one.ifr_hwaddr.sa_data[i] est déclaré en tant que tableau de caractères signés, mais votre tableau tab [] est non signé.

Les arguments de printf sont tous promus en int. Le caractère non signé, 0x86, est promu à 0x00000086, mais lorsque la même valeur est supposée être signée, il est promu à 0xFFFFFF86.

La promotion des nombres entiers frappe à nouveau!

Lorsque le spécificateur de conversion "x" est utilisé, les deux lignes printf et unsigned int .

Pour imprimer la moitié de la moitié d’un int signed ou unsigend signed (en supposant des unsigend 32 bits), utilisez le modificateur de longueur "h" deux fois:

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

Dans un cas, vous spécifiez comment la promotion se produit. Dans le second cas, vous ne le faites pas. La promotion doit être non signée. Donc, ne pas spécifier comment cela se produit conduit à des problèmes.

Si l’octet est 0x8f, vous avez besoin que cette valeur soit promue comme si le type n’était pas signé. Sinon, la préservation de la valeur nécessite la préservation du bit de signe.

La promotion conserve la même valeur. La manière dont les bits bruts sont interprétés comme une valeur lorsqu’ils sont promus fait donc une énorme différence.

Je soupçonne que one.ifr_hwaddr.sa_data est un tableau de caractères Un dans ce cas, un caractère signifie un caractère signé.

Ainsi, lorsqu’il est passé à travers la liste d’arguments variables de printf, il est promu int et printf l’affiche sous la forme unsigned int (spécificateur “x”)

Lorsqu’il est promu de char à int, le but du compilateur est de préserver sa valeur et non sa représentation binary.

0x86 est égal à 134 en tant que nombre décimal, traité comme caractère non signé et -122, traité comme caractère signé.

134 as unsigned int est représenté par 0x68 -122 comme int est représenté par 0xffffff86 (-1 comme int est 0xffffffff)

0xffffff86 est donc imprimé. Dans de tels cas (impression binary au format hexadécimal), j’utilise% 02hhx. Le spécificateur printf% hhx indique à printf de le traiter comme un caractère non signé, qui ne comporte qu’un octet.