2016-11-29 12 views
1

私は2つの異なるコンピュータで次の機能を使用しています。 1台のコンピュータがUbuntuと他のOS Xを実行しています。この機能はOS Xでは動作しますが、Ubuntuでは動作しません。文字列concatに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

コンパイルおよびOS XでXcodeで実行

ABC + DEF = ABCDEF

元の文字列= ABCDEF

  1. なぜMac上ではなくUbuntuの上でこの作品?
  2. Ubuntuで動作するはずですか?
  3. Macで動作するはずですか?
  4. 私は最近までUbuntuで動作することを誓っていたかもしれませんが、動作を止めるために何が変わったのでしょうか?
  5. コンパイラ設定はこの作業と関係がありますか?
+0

はstrncatです。 –

答えて

5

宛先コードをsnprintf()形式のソース文字列の1つとして渡すため、コードで未定義の動作が発生します。これはサポートされていません。

7.21.6.5 snprintf機能

あらすじ

#include <stdio.h> 

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

説明

snprintf機能は出力が書き込まれていることを除いて、fprintfに相当しますの配列ではなく、配列(引数sで指定)にストリーム。 nがゼロの場合、何も書き込まれず、sはNULLポインターになります。それ以外の場合は、n-1 st以降の出力文字は配列に書き込まれるのではなく破棄され、配列に実際に書き込まれる文字の末尾にヌル文字が書き込まれます。 重複するオブジェクト間でコピーが行われる場合、動作は未定義です。

(強調鉱山)。

snprintfの実装は、Ubuntu(glibc)とOS/X(BSDソースに基づいてApple libc)で異なります。動作は異なり、すべての場合に定義されていないため信頼できません。

あなたは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_strcatおよびsafe_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を上書きしているため、未定義の動作が発生しました。定義されていないため、なぜ1つのマシンで動作するのか他のマシンで動作しないのかは分かりません。

詳細はこちらをご覧ください。Is sprintf(buffer, "%s […]", buffer, […]) safe?

関連する問題