strcmp pour la chaîne vide

Je révisais du code et j'ai vu quelqu'un faire un

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

Je suis curieux parce que je pense qu'il serait plus rapide de faire un

if (foo[0] == '')

Est-ce correct ou strcmp est-il suffisamment optimisé pour les rendre identiques.

(je me rends compte que même s'il y avait une différence, ce serait petit, mais je pense que vous économisez au moins quelques instructions en utilisant ma méthode.)

25
demandé sur Shamim Hafiz 2011-06-01 18:47:28

8 réponses

Vous avez raison: puisque l'appel à strcmp() ajoute la gestion de la pile et le saut de mémoire aux instructions strcmp réelles, vous gagnerez quelques instructions en vérifiant simplement le premier octet de votre chaîne.

Pour votre curiosité, vous pouvez vérifier le code strcmp () ici: http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b091bd75c3fc93872dd71fe4b;hb=HEAD

(je pensais que le code serait rempli de #ifdef et obscur __GNUSOMETHING, mais c'est en fait plutôt simple!)

10
répondu Gui13 2011-06-01 15:14:27

Strcmp () est un appel de fonction et a donc une surcharge d'appel de fonction. foo [0] est un accès direct au tableau, donc c'est évidemment plus rapide.

9
répondu ralphtheninja 2011-06-01 15:00:37

Je ne vois aucun avantage à utiliser strcmp dans ce cas. Le compilateur est assez intelligent pour l'optimiser mais il ne sera pas plus rapide que de vérifier directement l'octet '\0'. L'implémenteur de ceci aurait pu choisir cette construction parce qu'il pensait qu'elle était plus lisible mais je pense que c'est une question de goût dans ce cas. Bien que j'écrirais le chèque un peu différent car c'est l'idiome qui semble être utilisé le plus souvent pour vérifier une chaîne vide:

if( !*str )

Et

if( *str )

Pour vérifier une chaîne non vide.

5
répondu x4u 2011-06-01 14:54:51

+ 1 à Gui13 pour fournir un lien vers la source de gcc stdlib strcmp (http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b091bd75c3fc93872dd71fe4b;hb=HEAD)!

Vous avez raison de dire que strcmp ne peut jamais être plus rapide qu'une comparaison directe[1], mais la question Est: le compilateur l'optimisera-t-il? J'ai été intimidé d'essayer de mesurer cela, mais j'ai été agréablement surpris de voir à quel point c'était facile. Mon exemple de code est (en omettant les en-têtes):

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

Et j'ai essayé compiler cela, d'abord avec gcc -S -o- emptystrcmptest.cc et ensuite avec gcc -S -O2 -o- emptystrcmptest.cc. À mon agréable surprise, bien que je ne puisse pas très bien lire l'assemblage, la version non optimisée a clairement montré une différence, et la version optimisée a clairement montré que les deux fonctions produisaient un assemblage identique.

Donc, je dirais qu'en général, il ne sert à rien de s'inquiéter de ce niveau d'optimisation.

Si vous utilisez un compilateur pour un système embarqué et que vous le savez pour ne pas gérer ce genre d'optimisation simple (ou n'avez pas du tout de bibliothèque standard), utilisez la version spéciale codée à la main.

Si vous codez normalement, utilisez la version la plus lisible (à mon humble avis qui peut être strcmp ou strlen ou [0] = = 0 selon le contexte).

Si vous écrivez du code très efficace, vous vous attendez à être appelé des milliers ou des millions de fois par seconde, (a) test qui est en fait plus efficace et (b) si la version lisible est en fait trop lente, essayez d'écrire somethign qui compilera pour mieux Assemblée.

Avec 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

Avec 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] bien que soyez prudent-dans les cas plus compliqués qu'un test direct contre zéro, le code de la bibliothèque et du compilateur a sera généralement meilleur que le code artisanal.

4
répondu Jack V. 2011-06-03 15:28:39

Un bon compilateur d'optimisation peut optimiser l'appel de fonction, puis éliminer la boucle de la fonction inline. Il n'y a aucun moyen que votre méthode puisse être plus lente, bien qu'il y ait une chance que ce soit la même vitesse.

1
répondu τεκ 2011-06-01 15:20:55

Accès à un tableau est d'ordre 1 en temps d'exécution, donc, son plus rapide que la fonction.

0
répondu mdaguerre 2011-06-01 14:52:25

C'est aussi micro-optimisation que possible, mais je suppose que si vous avez ajouté une vérification null avant d'indexer foo (sauf si vous savez que ce ne sera jamais null), cela économiserait techniquement la surcharge d'un appel de fonction.

0
répondu Brandon Moretz 2011-06-01 14:52:51

Cela va clairement être plus rapide, et il vaut probablement la peine de placer votre propre code dans une fonction en ligne, ou peut-être même une macro, si vous prévoyez d'aller de l'avant avec:

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;
}

Et laissez le compilateur optimiser cela pour vous. Quoi qu'il en soit, strcmp doit éventuellement vérifier '\0' de sorte que vous êtes toujours au moins égal à cela. (honnêtement, je laisserais probablement le compilateur optimiser le partage interne de ce qui précède, par exemple, {[3] } serait probablement juste flip isNotEmpty)

0
répondu pickypg 2011-06-01 14:59:41