4

文字列の終端のヌル文字へのポインタを取得する必要があります。

現在、私はこの単純な方法を使用してMyString + strlen(MyString)います。これはおそらく文脈から外れて非常に優れています。

ただし、文字列のコピーの後にそれを行う必要があるため、このソリューションには不快です。

char MyString[32];
char* EndOfString;
strcpy(MyString, "Foo");
EndOfString = MyString + strlen(MyString);

strcpyそのため、最初はで、2 回目は で、文字列を 2 回ループしていますstrlen

コピーされた文字数を返すカスタム関数を使用して、このオーバーヘッドを回避したいと思います。

size_t strcpylen(char *strDestination, const char *strSource)
{
    size_t len = 0;
    while( *strDestination++ = *strSource++ )
        len++;
    return len;
}

EndOfString = MyString + strcpylen(MyString, "Foobar");

ただし、私の実装は、コンパイラが提供する CRT 関数 (単純な char-by-char ループの代わりに、アセンブリの最適化またはその他のトリックを使用する可能性がある) よりも遅くなる可能性があるのではないかと心配しています。それとも、すでにそれを行っている標準の組み込み関数を認識していないのでしょうか?


0x1FFFFFFF を 3 つのアルゴリズム ( strcpy+ strlen、私のバージョンの、strcpylenおよびuser434507のバージョン) で反復して、貧弱なベンチマークを行いました。結果は次のとおりです。

1) strcpy+strlenはわずか 967 ミリ秒で勝者です。

2) 私のバージョンはもっと時間がかかります: 57 秒!

3) 編集されたバージョンは 53 秒かかります。

したがって、私の環境でカスタムの「最適化」バージョンの代わりに 2 つの CRT 関数を使用すると、50 倍以上高速になります。

4

8 に答える 8

5
size_t strcpylen(char *strDestination, const char *strSource)
{
    char* dest = strDestination;
    while( *dest++ = *strSource++ );
    return dest - strDestination;
}

これは strcpy の CRT バージョンが行うこととほとんど同じです。ただし、CRT バージョンでは、両方の引数が null でないことを確認するなどのチェックも行われます。

編集: VC++ 2005 の CRT ソースを見ています。pmg は正しく、チェックはありません。strcpy には 2 つのバージョンがあります。1 つはアセンブリで記述され、もう 1 つは C で記述されています。C バージョンは次のとおりです。

char * __cdecl strcpy(char * dst, const char * src)
{
        char * cp = dst;

        while( *cp++ = *src++ )
                ;               /* Copy src over dst */

        return( dst );
}
于 2010-11-13T14:20:56.293 に答える
5

Hacker's Delightには、C 文字列の最初のヌル バイトを見つけることに関するすばらしいセクションがあります (第 6 章セクション 1 を参照)。Google ブックスでそれ (の一部) を見つけました。コードはここにあるようです。いつもこの本に戻ってきます。お役に立てば幸いです。

于 2010-11-13T14:32:03.437 に答える
1

いくつかの注意事項:関数があまり頻繁に呼び出されない場合、コードはすでにCPUキャッシュにあるため、Cライブラリよりもコードから実行する方が高速である可能性があります。

ベンチマークが行っているのは、ライブラリ呼び出しがキャッシュ内にあることを確認することです。これは、実際のアプリケーションでは必ずしも当てはまりません。

さらに、インラインになると、さらに多くのサイクルを節約できます。コンパイラとCPUは、分岐予測とデータのプリフェッチにリーフ関数呼び出し(複数の呼び出しレベルではなく1レベルのカプセル化)を優先します。

それは、コードスタイル、アプリケーション、およびサイクルを節約する必要がある場所によっても異なります。

ご覧のとおり、画像は以前に露光されたものよりも少し複雑です。

于 2010-12-19T17:32:45.360 に答える
1

を使用するstrlcpy()と、コピーしたものの長さが返されます ( size パラメータが十分に大きいと仮定します)。

于 2010-11-13T14:18:04.717 に答える
1

これを試すことができます:

int len = strlen(new_str);
memcpy(MyString, new_str, len + 1);
EndOfString = MyString + len;

new_strが大きい場合にのみ意味があります。これは、memcpy標準while( *dest++ = *strSource++ );のアプローチよりもはるかに高速ですが、初期化コストが余分にかかるためです。

于 2010-11-13T15:07:28.877 に答える
0

ここであなたは不必要に心配しているかもしれないと思います。ここで得られる可能性のある利益は、他の場所で行うことができるより良い改善によって相殺される以上のものになる可能性があります. 私のアドバイスは、これについて心配することではなく、コードを完成させて、この最適化の利点が追加の作業と将来の保守作業を高速化することよりも重要であるほど処理サイクルが不足しているかどうかを確認することです。

要するに:それをしないでください。

于 2010-11-13T14:22:01.317 に答える
0

試してくださいmemccpy()(または_memccpy()VC 2005+で)。strcpy + strlenとあなたのカスタムアルゴリズムに対していくつかのテストを実行しましたが、私の環境では両方に勝っていました。ただし、私にとってあなたのアルゴリズムはあなたが見たよりもはるかに高速に実行され、はるかに遅く実行されるため、それがあなたのアルゴリズムでどれだけうまく機能するかはわかりませんstrcpy + strlen(前者の場合は 14.4 秒、後者の場合は 7.3 秒、反復回数を使用)。 . 以下のコードのクロックは約 5 秒でした。

int main(int argc, char *argv[])
{
    char test_string[] = "Foo";
    char new_string[64];
    char *null_character = NULL;
    int i;
    int iterations = 0x1FFFFFFF;

    for(i = 0; i < iterations; i++)
    {
        null_character = memccpy(new_string, test_string, 0, 64);
        --null_character;
    }

    return 0;
}
于 2010-11-14T07:01:43.267 に答える
-2

チェックアウトしてくださいsprintf
http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/

于 2010-11-13T14:13:30.620 に答える