31

私はいくつかのコードをレビューしていました、そして私は誰かがするのを見ました

if (0 == strcmp(foo,""))

私は興味があります。

if (foo[0] == '\0')

これは正しいですか、またはstrcmpはそれらを同じにするのに十分最適化されていますか?

(多少の違いがあっても小さいと思いますが、私の方法で少なくともいくつかの指示を節約できると思います。)

4

8 に答える 8

11

その通りです。呼び出しstrcmp()によってスタック管理が追加され、メモリが実際のstrcmp命令にジャンプするため、文字列の最初のバイトをチェックするだけで、いくつかの命令を取得できます。

好奇心については、ここでstrcmp()コードを確認できます:http ://sourceware.org/git/?p = glibc.git; a = blob; f = string / strcmp.c; h = bd53c05c6e21130b091bd75c3fc93872dd71fe4b; hb = HEAD

#ifdef(コードはいっぱいになり、わかりにくくなると思いました__GNUSOMETHINGが、実際にはかなり単純です!)

于 2011-06-01T14:50:54.633 に答える
9

strcmp()は関数呼び出しであるため、関数呼び出しのオーバーヘッドがあります。foo [0]は配列に直接アクセスするため、明らかに高速です。

于 2011-06-01T14:49:46.323 に答える
5

この場合、strcmpを使用する利点はありません。コンパイラはそれを最適化するのに十分賢いかもしれませんが、'\0'バイトを直接チェックするよりも速くはありません。これの実装者は、より読みやすいと思ったのでこの構成を選択したかもしれませんが、この場合、これは好みの問題だと思います。これは空の文字列をチェックするために最も頻繁に使用されると思われるイディオムであるため、チェックの記述は少し異なりますが、次のようになります。

if( !*str )

if( *str )

空でない文字列をチェックします。

于 2011-06-01T14:54:51.893 に答える
4

gcc stdlib strcmpのソースへのリンクを提供するためのGui13への+1(http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b091bd75c3fc93872dd71fe4b;hb = HEAD)!

strcmpが直接比較[1]より速くなることは決してないというのは正しいですが、問題は、コンパイラーがそれを最適化するかどうかです。それを測ってみるのは怖かったのですが、その簡単さに驚きました。私のサンプルコードは(ヘッダーを省略)です:

bool isEmpty(char * str) {
   return 0==std::strcmp(str,"");
}
bool isEmpty2(char * str) {
   return str[0]==0;
}

gcc -S -o- emptystrcmptest.ccそして、最初にで、次にでコンパイルしてみましたgcc -S -O2 -o- emptystrcmptest.cc。驚いたことに、アセンブリをよく読むことはできませんが、最適化されていないバージョンは明らかに違いを示し、最適化されたバージョンは2つの関数が同じアセンブリを生成することを明確に示しました。

したがって、一般的に、このレベルの最適化について心配する必要はありません。

組み込みシステム用のコンパイラを使用していて、この種の単純な最適化を処理できないことがわかっている場合(または標準ライブラリがまったくない場合)は、手書きの特殊なケースのバージョンを使用してください。

通常のコーディングをしている場合は、より読みやすいバージョンを使用してください(コンテキストに応じて、strcmpまたはstrlenまたは[0] == 0のimho)。

1秒間に数千回または数百万回呼び出されると予想される非常に効率的なコードを記述している場合、(a)実際にはより効率的なテスト、(b)読み取り可能なバージョンが実際に遅すぎる場合は、コンパイルされる何かを記述してみてください。より良いアセンブリ。

gcc -S -o- emptystrcmptest.cc

            .file   "emptystrcmptest.cc"
            .section .rdata,"dr"
    LC0:
            .ascii "\0"
            .text
            .align 2
    .globl __Z7isEmptyPc
            .def    __Z7isEmptyPc;  .scl    2;      .type   32;     .endef
    __Z7isEmptyPc:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $24, %esp
            movl    $LC0, 4(%esp)
            movl    8(%ebp), %eax
            movl    %eax, (%esp)
            call    _strcmp
            movl    %eax, -4(%ebp)
            cmpl    $0, -4(%ebp)
            sete    %al
            movzbl  %al, %eax
            movl    %eax, -4(%ebp)
            movl    -4(%ebp), %eax
            leave
            ret
            .align 2
    .globl __Z8isEmpty2Pc
            .def    __Z8isEmpty2Pc; .scl    2;      .type   32;     .endef
    __Z8isEmpty2Pc:
            pushl   %ebp
            movl    %esp, %ebp
            movl    8(%ebp), %eax
            cmpb    $0, (%eax)
            sete    %al
            movzbl  %al, %eax
            popl    %ebp
            ret
    emptystrcmptest.cc:10:2: warning: no newline at end of file
            .def    _strcmp;        .scl    2;      .type   32;     .endef

gcc -S -O2 -o- emptystrcmptest.cc

        .file   "emptystrcmptest.cc"
emptystrcmptest.cc:10:2: warning: no newline at end of file
        .text
        .align 2
        .p2align 4,,15
.globl __Z7isEmptyPc
        .def    __Z7isEmptyPc;  .scl    2;      .type   32;     .endef
__Z7isEmptyPc:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        popl    %ebp
        cmpb    $0, (%eax)
        sete    %al
        movzbl  %al, %eax
        ret
        .align 2
        .p2align 4,,15
.globl __Z8isEmpty2Pc
        .def    __Z8isEmpty2Pc; .scl    2;      .type   32;     .endef
__Z8isEmpty2Pc:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        popl    %ebp
        cmpb    $0, (%eax)
        sete    %al
        movzbl  %al, %eax
        ret

[1]注意が必要ですが、ゼロに対する直接テストよりも複雑な場合は、ライブラリとコンパイラのコードは通常、手作りのコードよりも優れています。

于 2011-06-03T15:28:39.387 に答える
1

優れた最適化コンパイラは、関数呼び出しを最適化してから、インライン関数からループを排除する場合があります。同じ速度になる可能性はありますが、メソッドが遅くなる可能性はありません。

于 2011-06-01T15:20:55.260 に答える
0

配列へのアクセスは実行時間の1次であるため、関数よりも高速です。

于 2011-06-01T14:52:25.810 に答える
0

これは可能な限りマイクロ最適化ですが、fooにインデックスを付ける前にnullチェックを追加した場合(nullになることがないことがわかっている場合を除く)、技術的には関数呼び出しのオーバーヘッドを節約できると思います。

于 2011-06-01T14:52:51.620 に答える
0

それは明らかに速くなるでしょう、そしてあなたがそれを進めることを計画しているなら、それはおそらくあなた自身のコードをインライン関数、あるいは多分マクロに置く価値があります:

int isEmpty(const char *string)
{
    return ! *string;
}

int isNotEmpty(const char *string)
{
    return *string;
}

int isNullOrEmpty(const char *string)
{
    return string == NULL || ! *string;
}

int isNotNullOrEmpty(const char *string)
{
    return string != NULL && *string;
}

コンパイラに最適化させてください。とにかく、あなたが常に少なくともそれに等しいようにstrcmp、最終的にチェックする必要があります。'\0'(正直なところ、私はおそらくコンパイラに上記の内部共有を最適化させるでしょう、例えば、isEmptyおそらく単に反転するでしょうisNotEmpty

于 2011-06-01T14:59:41.527 に答える