2010-11-11 47 views
0

我有以下程序,它正在崩潰。有人知道它爲什麼會崩潰嗎?在C中使用sizeof

/* writes a, b, c into dst 
** dst must have enough space for the result 
** assumes all 3 numbers are positive */ 
void concat3(char *dst, int a, int b, int c) { 
    sprintf(dst, "%08x%08x%08x", a, b, c); 
} 

/* usage */ 
int main(void) { 
    printf("The size of int is %d \n", sizeof(int)); 
    char n3[3 * sizeof(int) + 1]; 
    concat3(n3, 0xDEADFACE, 0xF00BA4, 42); 
    printf("result is 0x%s\n", n3); 
    return 0; 
} 
+7

每次使用'sprintf',我殺了一隻小貓。 – 2010-11-11 13:30:49

+0

這是C還是C++?他們不是同一種語言。 – 2010-11-11 13:46:01

+0

此問題是由同一張海報對[生成唯一編號](http://stackoverflow.com/q/4143473/25324)問題的後續處理。 – pmg 2010-11-11 14:31:15

回答

13

你混淆了二進制數據的大小(這是什麼sizeof)給你,用文字表述的十六進制的大小,這是你想要什麼店。

在大多數當前系統上,sizeof(int)的計算結果爲4.因此,緩衝區n3將能夠存儲13個字符(3 * 4 + 1 == 13)。

然後,您將三個整數格式化爲8字符的十六進制格式,這需要3 * 8 + 1 == 25個字符來存儲。由此產生的緩衝區溢出導致崩潰。

數據類型int的大小應該很明顯,當您將其格式化爲文本(並且自己指定字段寬度!)時。

+0

你可以請好嗎? – Venkata 2010-11-11 13:29:09

+1

12 + 1字節:-) – Konrad 2010-11-11 13:29:43

+0

要保存字符串「0xDEADFACE」,您需要11個字節(內容10個,nul字符1個)。這比保存大多數系統只有4個字節的整數所需的字節大得多。 – Neil 2010-11-11 13:35:47

0

它正在崩潰,因爲sizeof(int)(最有可能在您的系統上)4,這意味着n3的長度爲13個字節。然後嘗試將8 + 8 + 8 = 24個字符寫入它。

1

我真的不明白sizeof在代碼中有什麼要做的。在concat3中,您試圖將每個提供的整數的文本表示形式打印爲8個字符的十六進制字符串:因此所需的緩衝區大小應該等於8 * 3 + 1 = 25,而sizeof(int)與此無關。

你似乎在用int來混合內存中佔用的大小,以及它的文本表示的長度(在你的情況下它很容易確定,因爲它是由你的sprintf格式字符串修復的)。

附註:sprintf是一個真正不安全的函數,您應該考慮棄用。

+0

誰不推薦'sprintf'?哪裏?什麼時候?我想哭... – pmg 2010-11-11 14:32:21

+0

振作起來,沒有人做:)我的意思是'sprintf'應該不會出現在新編寫的代碼中,並且'snprintf'應該被考慮。你不同意嗎? – icecrime 2010-11-11 14:36:53

+1

基本上,是的。但實際上沒有,並不是真的。 'snprintf'不會使字符串管理更簡單,因爲您仍然需要跟蹤字符串長度和分配大小。使用'snprintf'不會阻止像'char s [2];/* ...在一個子程序內部很深的地方...... */snprintf(s,7,「foobar」);' – pmg 2010-11-11 15:21:29

0

使用snprintf代替sprintf。想想小貓!

但嚴重的是,你不應該創建接口與緩衝區指針,但沒有長度信息。 concat應該有一個最大長度參數。然後在裏面使用snprintf。 concat的長度是sizeof(n3)。

它仍然無法工作,但它也不會崩潰。其他答案解釋瞭如何獲得正確的功能。

(呵呵,不要使用gets()兩種。正因爲它是在標準庫並不意味着它是很好的代碼。)

+0

你把'puts'和'gets'混淆了嗎? 'puts'沒有問題。這是最有效的方式(就生成的代碼大小和可能的性能而言)來打印以換行符結尾的不變文本行。現代的gcc甚至用一個不包含格式說明符的常量參數替換'printf',並以'puts'調用結束於換行符。 – 2010-11-11 18:49:57

2

嘗試3*2*sizeof(int)+1,其中2*sizeof(int)是所需的字節數以十六進制打印int的每個字節。當然,因爲您使用的格式爲%08X,並且期望得到固定寬度的結果,所以您確實應該使用uint32_t。順便說一句,您的程序也錯誤地將0xDEADBEEF作爲int,它可能不適合,從而進入實現定義的轉換爲簽名類型的領域。

下面是這些更正一個版本:

#include <inttypes.h> 
#include <stdio.h> 

/* writes a, b, c into dst 
** dst must have enough space for the result 
** assumes all 3 numbers are positive */ 
void concat3(char *dst, uint32_t a, uint32_t b, uint32_t c) { 
    sprintf(dst, "%08"PRIX32"%08"PRIX32"%08"PRIX32, a, b, c); 
} 

/* usage */ 
int main(void) { 
    printf("The size of int is %d \n", sizeof(int)); 
    char n3[25]; 
    concat3(n3, 0xDEADFACE, 0xF00BA4, 42); 
    printf("result is 0x%s\n", n3); 
    return 0; 
} 
+1

對於'sprintf'格式的字符串,你想要''%08「PRIx32)'而不是''%08」PRIu32「x」'。 – pmg 2010-11-11 18:13:47

+0

Doh,固定..... – 2010-11-11 18:48:15