2014-03-27 58 views
0

我附加了這個問題的代碼應該獲取設備的mac地址並將其打印出來。它將數據從結構ifreq複製到uint8_t數組時,它工作正常,但當我不這樣做時,會得到奇怪的結果。看看第二行,輸出的第二個字節。奇怪的printf()行爲

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

OUTPUT:

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

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

+0

你的問題是什麼?你爲什麼期望別的嗎? ('printf'通過參數傳遞'...',如果你需要類型提升發生一些特定的方式,你必須指定。編譯器不能用魔法知道) –

+0

的printf(「%02X:」 ......可以打印8個字符 – Taiki

+2

@Taiki當然你會想到這個代碼做?'的printf(「%02X」,5000 );'甚至'的printf(「%02X」,-1);?' –

回答

0

在一種情況下,你指定促銷發生的方式。在第二種情況下,你不這樣做。您需要將促銷信息無簽名。所以不指定它如何發生會導致問題。

如果字節是0x8f,那麼需要將該值升級,就好像該類型是無符號的。否則,保留該值需要保留符號位。

促銷保持價值相同。因此,它們在升級時如何將原始位數解釋爲一個值,這會產生巨大的差異。

4

你問爲什麼第二個字節打印爲ffffff86而不是86?這是因爲它已被簽名擴展。 one.ifr_hwaddr.sa_data[i]數組被聲明爲一個有符號字符數組,但是你的tab []數組是無符號的。

將參數printf全部提升爲int。無符號字符0x86被提升爲0x00000086,但是當假定相同的值被簽名時,它將被提升爲0xFFFFFF86。

1

整數推廣再次襲擊!

由於使用轉換說明符"x",所以使用了兩行printfunsigned int

要打印signedunsigendint(假定32位整數)的一半的半使用length modifer "h"兩次:

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

+1爲 「HH」,但目前還不清楚爲什麼 「0」 的格式爲你在想' 「%02hhx:」' – chux

+0

@chux:我個人的接待顯示,02 ... - 感謝您通知。?! – alk

0

我懷疑,這是one.ifr_hwaddr.sa_data字符 的陣列的在這種情況下的字符表示有符號的char

所以,當通過的printf的變量參數列表過去了,它提升爲int和printf打印出來爲unsigned int(「X」符)

當從焦炭提升爲int,編譯器的目標是保持其值 - 不是它的二進制表示。

0x86爲十進制134,視爲無符號字符和-122,視爲有符號字符。作爲INT表示爲0xffffff86(-1作爲int是爲0xFFFFFFFF)

因此,被印刷0xffffff86

134爲unsigned int表示爲0x68 -122。 在這種情況下(打印二進制爲十六進制)我使用%02hhx printf說明符 %hhx告訴printf將其視爲一個無符號字符 - 它只有1個字節。