3

私は、ファイル形式が各ビットに固有である、いくつかの低レベルのファイル書き込みの実装に取り​​組んでいます。文字列を長さ16のnullで終了する文字列にコピーする必要がありますNSString(Xcodeによると割り当てられません)。私は合計n00bcあり、これを正しく理解していることを確認したいと思います。これは私が現在行っていることです:

//I have a non-null NSString called _friendly_name.
const char *string = [_friendly_name UTF8String];
//profile.friendly is a utf-8 null-terminated string
memcpy(&profile.friendly_name, &string, 16);

これはまだテストされていませんが、これが機能することを確認したいと思います。これは私が期待している動作を提供しますか?または、文字列を別の方法(などstrcpy)でコピーする必要がありますか?

4

4 に答える 4

4

memcpy()またはを使用できstrcpy()ますが、境界チェックを自分で行う必要があり、コードに他のエラーがあります。

char[16]したがって、NSStringを配列にコピーしたいと思います。組み込みのメソッドを使用してこれを行うことができ、自分NSStringで使用する必要はありません。memcpy()

NSString *src;
char dest[16];
NSUinteger destlen;
[src getBytes:dest
    maxLength:sizeof(dest) - 1
    usedLength:&destlen
    encoding:NSUTF8StringEncoding
    options:0
    range:NSMakeRange(0, [src length])
    remainingRange:NULL];
dest[destlen] = '\0';

を使用する場合はmemcpy()、次のようにする必要があります。

NSString *src;
char dest[16], *srcUtf8;
size_t len;

srcUtf8 = [src UTF8String];
len = strlen(srcUtf8);
if (len >= sizeof(dest))
    len = sizeof(dest) - 1;
memcpy(dest, srcUtf8, len);
dest[len] = '\0';

コードのエラー

このコードには2つのエラーがあります!

memcpy(&profile.friendly_name, &string, 16); // Wrong!

まず第一に、&string間違っています。stringは、コピーする文字列データへのポインタであるため、である必要がありstringます。をコピー&stringすると、代わりにポインタとスタックデータのランダムビットがコピーされます。言い換えれば、あなたはゴミを得るでしょう。

第二に、16は間違っています。string少なくとも16バイトのデータを指していることがわかっている場合にのみ、16バイトをコピーできます。stringこれにより、 16バイト未満の場合、メモリ内の次のデータが読み取れない場合、セグメンテーション違反(プログラムのクラッシュ、ハード)が発生します。今日はクラッシュしないかもしれませんが、来週はクラッシュするかもしれません。あなたはそれについてすべて忘れているでしょうか?

間違っています。ソースの長さが16バイト以上であることがわかっている場合を除いて、16を渡さないでください。

于 2013-02-18T23:11:02.977 に答える
3

memcpy()は正常に動作するはずですが、strcpy()も正常に動作します。profile.friendly_nameが、コピー先を保持するのに十分な大きさであることを確認する必要があります。

于 2013-02-18T22:52:57.267 に答える
2

ドキュメントを読んだことがありますか?memcpyは機能しますが、コピーするバイト数を渡します。NULLに関係なく、指定したバイト数をコピーします。strcpyは長さを渡さないで、最初のNULLまでのバイトをコピーします。

http://www.cplusplus.com/reference/cstring/memcpy/

http://www.cplusplus.com/reference/cstring/strcpy/

于 2013-02-18T22:59:23.307 に答える
0
//I have a non-null NSString called _friendly_name.
const char *string = [_friendly_name UTF8String];
//profile.friendly is a utf-8 null-terminated string  : char [17] ??
memcpy(profile.friendly_name, string, 16);
profile.friendly_name[16]='\0';

編集:はい、その通りです。NULLエンデを追加します。0実際には、コピーする前にすべてに初期化する方がよい場合があります。前の位置16がstrcpyないと機能_friendly_nameしません。問題ありません。'\0'strncpy

EDIT2:

必要な情報がすべて揃っていない理由として、いくつかの問題が発生しました。

1-長さ16(16文字+ 0のように)のNULLで終了する文字列が必要です。または、 ?char var[17];のように16バイトのフィールドで終了するwitchNULLが必要です。char var[16];

2-必要な「エラー」管理とは何ですか。元の文字列が「16」よりも大きい場合は、それを切り捨てるか、エラーをスローしますか?

16バイトのフィールドと、使用できる切り捨て文字列が必要であると仮定します。

strncpy(profile.friendly_name, string, 15);
profile.friendly_name[15]='\0';

EDIT3:

また...切り捨てるには注意深く行う必要があります。マルチバイト文字を切り捨てたくないのです...

于 2013-02-18T22:55:24.980 に答える