2016-11-29 218 views
1

我在兩臺不同的計算機上使用以下功能。一臺電腦運行Ubuntu和另一臺OS X.該功能適用​​於OS X,但不適用於Ubuntu。c snprintf用於連接字符串

#include <stdio.h> 

#define MAXBUF 256 

char *safe_strncat(char *dest, const char *src, size_t n) { 
    snprintf(dest, n, "%s%s", dest, src); 
    return dest; 
} 

int main(int argc, const char * argv[]){ 
    char st1[MAXBUF+1] = "abc"; 
    char st2[MAXBUF+1] = "def"; 
    char* st3; 
    printf("%s + %s = ",st1, st2); 

    st3 = safe_strncat(st1, st2, MAXBUF); 

    printf("%s\n",st3); 
    printf("original string = %s\n",st1); 
} 

編譯並在Ubuntu運行

GCC concat_test.c -o concat_test

./concat_test

ABC DEF + = DEF

原始字符串= DEF

編譯並在Xcode在OS X上運行

ABC + DEF = ABCDEF

原始字符串= ABCDEF

  1. 爲什麼在Mac上,而不是在Ubuntu這項工作?
  2. 它應該在Ubuntu上運行嗎?
  3. 它應該在Mac上工作嗎?
  4. 我可以發誓它曾經在Ubuntu上工作,直到最近,但我不知道會改變什麼使它停止工作?
  5. 編譯器設置是否與這個工作有關?
+0

是strncat函數一個很好的選擇? –

回答

5

您的代碼會調用未定義的行爲,因爲您將目標緩衝區作爲snprintf()格式的源字符串之一傳遞。這是不支持:

7.21.6.5的snprintf功能

梗概

#include <stdio.h> 

int snprintf(char * restrict s, size_t n, 
      const char * restrict format, ...); 

說明

snprintf功能相當於fprintf,不同之處在於輸出寫入到數組中(由參數s指定)而不是a流。如果n爲零,則不會寫入任何內容,並且s可能是空指針。否則,超出n-1 st的輸出字符將被丟棄,而不是寫入數組,並且在實際寫入數組的字符末尾寫入空字符。 如果在重疊的對象之間進行復制,則行爲未定義。

(強調我的)。

snprintf的實現在Ubuntu(glibc)和OS/X(Apple libc,基於BSD源)之間有所不同。行爲有所不同,不能依賴,因爲它在所有情況下都是未定義的。

您可以實現safe_strcat()這樣:

#include <string.h> 

char *safe_strcat(char *dest, size_t size, const char *src) { 
    char *p = memchr(dest, '\0', size); 
    if (p != NULL) { 
     strncat(p, src, size - (p - dest) - 1); 
    } 
    return dest; 
} 

注:

  • 不調用此函數safe_strncat(),它是真正的strcat()安全的版本。
  • 傳遞目標數組後的目標數組的大小,而不是源指針之後。
  • 返回目標指針不允許調用方檢測截斷。如果目標數組已足夠大,您可以返回結果的長度,如snprintf(),如果在調用之前目標未終止(對於safe_strcatsafe_strncat),它仍不會告訴調用方。

您可以使用的strcpystrncatstrncpy(但不執行strncpy()的反直覺的語義)安全版本的同一型號:

char *safe_strcpy(char *dest, size_t size, const char *src) { 
    if (size > 0) { 
     *dest = '\0'; 
     strncat(dest, src, size - 1); 
    } 
    return dest; 
} 

char *safe_strncat(char *dest, size_t size, const char *src, size_t n) { 
    char *p = memchr(dest, '\0', size); 
    if (p != NULL) { 
     if (n > size - (p - dest) - 1) 
      n = size - (p - dest) - 1; 
     strncat(p, src, n); 
    } 
    return dest; 
} 

char *safe_strncpy(char *dest, size_t size, const char *src, size_t n) { 
    if (size > 0) { 
     if (n > size - 1) 
      n = size - 1; 
     *dest = '\0'; 
     strncat(dest, src, n); 
    } 
    return dest; 
} 
2

的snprintf(DEST,N,「 %s%s「,dest,src);

此行導致未定義的行爲,因爲您覆蓋緩衝區dest。因爲它沒有定義,所以找出爲什麼它在一臺機器上運行而不是另一臺機器是毫無意義的。

更多細節可以在這裏找到:Is sprintf(buffer, "%s […]", buffer, […]) safe?