2010-07-08 52 views
0

我沒有使用C很多時間,現在我不得不修改一小段代碼。有一件事我不明白:C,sprintf和字符串和int的「求和」

char filename[20]; 
filename[0] = '\0'; 
for (j=0; j < SHA_DIGEST_LENGTH; j++){ 
    sprintf(filename + strlen(filename),"%02x",result[j]); 
} 

在第一行中,一個由20個字符組成的字符串被縮放。 在第二行中,第一個字符被設置爲'\ 0',我想這是一個空字符串。

在for循環中,我不理解文件名和它的長度之間的「總和」...... sprintf的firs參數應該是一個緩衝區,它將右側的格式化字符串複製到此處。這筆錢的結果是什麼?在我看來,我試圖總結一個數組和整數...

我失蹤了什麼?

回答

13

它是指針算術。 strlen返回NUL終止符之前的字符數。添加的結果將指向此終結符。例如。如果當前字符串是「AA」(後跟NUL),則strlen爲2. filename + 2指向NUL。它會在NUL和下一個字符上寫入下一個十六進制字符(例如BB)。然後它將再次終止它(在filename + 4)。那麼你會有「AABB」(然後是NUL)。

雖然這並沒有什麼意義。它浪費了很多時間尋找那些NUL。具體來說,這是一個二次算法。第一次檢查1個字符,然後檢查3,5,7,...,2 * SHA_DIGEST_LENGTH - 1)。它可能只是:

sprintf(filename + 2 * j,"%02x",result[j]); 

還有另一個問題。 SHA-1總和的十六進制表示需要40個字符,因爲一個字節需要兩個字符。然後,你有一個最終的NUL終止符,所以應該有41個。否則,會有一個緩衝區溢出。

+0

如果你這樣做,不要忘記手動將其終止。 – zebediah49 2010-07-08 10:09:19

+0

@zebediah,你是什麼意思? sprintf將始終添加一個NUL終結符。 – 2010-07-08 10:13:34

+0

'它會在這個NUL上寫下一個十六進制字符(例如C),然後NUL-termiante再次'默認情況下'sprintf'是否添加'\ 0'? – Amarghosh 2010-07-08 10:14:33

0

要添加的strlen(文件名)僅做結果的拼接[J]

每次迭代地連接了當前的結果[J]在文件名末尾所以每次你都需要時間知道文件名中的偏移串聯應該在哪裏進行。

1

第一次迭代中,當j = 0,就會寫3個字符(是的,包括'\0'終止字符串)到的filename開始時,由於函數strlen(),然後返回0。 接着圓形,strlen的()返回圖2,和它會在前兩個字符後繼續寫入。

小心踩出分配的20個char空間。常見的錯誤是忘記字符串終結符所需的空間。

編輯:確保SHA_DIGEST_LENGTH不大於9

1

你爲什麼不申報

char filename[SHA_DIGEST_LEN*2 +1];/*和+1如果你想有NULL終止符*/

這是因爲SHA1摘要長度是20個字節,如果你只是打印摘要,那麼你可能不想額外的內存,但因爲你想要摘要的十六進制字符串,你可以使用上面的聲明。 strlen操作返回字符串的長度,直到遇到空終止字符。

所以當你執行以下操作基本上是:

sprintf(filename + strlen(filename),"%02x",result[j]); 

在第一互爲作用FILNAME用2個字節的SHA-1摘要的第一個字節的十六進制表示的複製。例如。說這是AA,現在你需要移動你的指針兩個地方複製下一個字節。

第二次迭代後,它成爲AABB。 在第20次迭代之後,如果需要'\ 0'(NULL終止字符),則您有整個字符串AABBCC ...... AA [40個字節]和+1。

0

與替換代碼:

char filename[SHA_DIGEST_LENGTH*2+1]; 
for (j=0; j < SHA_DIGEST_LENGTH; j++){ 
    sprintf(filename + 2*j,"%02x",result[j]); 
} 

更快,更簡單,蟲子都沒有了。