2015-07-21 23 views
-1

當我在sprintf()應用程序中使用%u使用被撞壞,它與%d格式說明%u與sprintf的是創造碰撞

做工精細看到代碼:

#include <stdio.h> 
#include <string.h> 
main() 
{ 
    unsigned char dAddr[4]; 
    unsigned char sMask[4]; 
    unsigned char nHop[4]; 
    memset(dAddr,0,sizeof(dAddr)); 
    memset(sMask,0,sizeof(sMask)); 
    memset(nHop,0,sizeof(nHop)); 
    unsigned int u4IpDAddr = 0x01020304; 
    unsigned int u4IpSNetMask = 0xffff01ff; 
    unsigned int u4NHopGt = 0x01020304; 
    char *dip = (char *)&u4IpDAddr; 
    char *smk = (char *)&u4IpSNetMask; 
    char *nhp = (char *)&u4NHopGt; 
    sprintf(dAddr, "%u.%u.%u.%u", dip[3], dip[2], dip[1], dip[0]); //if I used %d.%d.%d.%d its working fine 
    sprintf(sMask, "%u.%u.%u.%u", smk[3], smk[2], smk[1], smk[0]); //if I used %d.%d.%d.%d its working fine 
    sprintf(nHop, "%u.%u.%u.%u", nhp[3], nhp[2], nhp[1], nhp[0]); //if I used %d.%d.%d.%d its working fine 
    printf("SAM: func %s line %d IpDAddr %s Mask %s NHop %s\n",__func__,__LINE__,dAddr,sMask,nHop); 
} 

當我宣佈一個指針與以下方式其工作正常%u.%u.%u.%u格式

unsigned char *dip = (unsigned char *)&u4IpDAddr; 
unsigned char *smk = (unsigned char *)&u4IpSNetMask; 
unsigned char *nhp = (unsigned char *)&u4NHopGt; 

可以任何一個解釋我什麼當我使用char指針?

+4

這是瘋狂的代碼。你想要做什麼? – ooga

+2

Sourav已經給出了唯一真正的答案。你超出了你的數組邊界(兩種方式),結果是不確定的。然而,根據你的數據和你環境中默認的'char'的符號性,當你使用普通的'char'指針時,由於重新解釋一個負數的有符號數,你可能會超越你的數組*一個'char'升級爲'int')作爲一個無符號的。這可以解釋爲什麼觀察到的(未定義的)結果不同。 –

+0

在'smk'中使用'%u'會導致未定義的行爲。 '%u'只用於打印無符號整數(或帶有非負值的整數),但某些「smk」的值是負數字符。 –

回答

9

在你的情況

unsigned char dAddr[4]; 
unsigned char sMask[4]; 
unsigned char nHop[4]; 

不足以容納辭書輸出。

當您在sprintf()中使用這些陣列作爲目標字符串時,實際上,您超出了分配的內存,從而創建了undefined behaviour

您需要分配更多內存才能將這些陣列用作sprintf()的目標。

1

如果char在你的平臺上簽字,然後char值您在u4IpSNetMask的「砍了」比可能是負面的多,因爲你有在u4IpSNetMask0xF...開始字節。當您將這樣的char值發送到sprintf時,它們將轉換爲負值int值,然後通過您的%u說明符重新解釋爲值unsigned。該行爲實際上是未定義的 - sprintfint值與%u是非法的。然而,在實踐中,你通常會得到一個巨大的正面價值觀,需要很多人物來表達。這些表示很容易溢出目標緩衝區,破壞程序堆棧並導致程序崩潰。

你可以自己看看你sprintf電話生成一個典型的平臺:http://coliru.stacked-crooked.com/a/6aec03cfdf28f8b2

中間sprintf產生4294967295.4294967295.1.4294967295。你期望這個怪物適合只有4個字符長的緩存sMask

此外,相同類型的溢流用%d發生爲好,但由%d產生的字符串表示(代替4294967295-1)的傷害更小,這可能是爲什麼所述節目排序的顛到較短最終不會崩潰。但是這並不改變字符串1.2.3.4需要長度至少爲8個字符的字符緩衝區這一事實。您只提供了4.

換句話說,您的程序與%d一樣損壞,因爲它與%u有關。如果它沒有與%d一起崩潰,那只是偶然的運氣。