una texto recorrer que primera operaciones letra imprimir función ejercicios devuelva crear con caracteres cadenas cadena arreglo c strcmp

texto - recorrer una cadena en c



strcmp para cadena vacía (8)

Estaba revisando un código y vi a alguien hacer una

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

Tengo curiosidad porque creo que sería más rápido hacer un

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

¿Es correcto o es strcmp lo suficientemente optimizado para hacer que sean iguales?

(Me doy cuenta de que incluso si hubiera alguna diferencia sería pequeña, pero estoy pensando que puedes guardar al menos algunas instrucciones usando mi método).


+1 a Gui13 por proporcionar un enlace a la fuente de gcc stdlib strcmp (http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b3fc93872dd71fe4b; h = CABEZA)!

Tienes razón en que strcmp nunca puede ser más rápido que una comparación directa [1], pero la pregunta es, ¿el compilador lo optimizará? Me intimidó intentar medirlo, pero me sorprendió gratamente lo fácil que fue. Mi código de ejemplo es (omitiendo encabezados):

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

Y traté de compilar eso, primero con gcc -S -o- emptystrcmptest.cc y luego con gcc -S -O2 -o- emptystrcmptest.cc . Para mi grata sorpresa, aunque no puedo leer el ensamblaje muy bien, la versión no optimizada mostró claramente una diferencia, y la versión optimizada mostró claramente que las dos funciones produjeron un ensamblaje idéntico.

Por lo tanto, diría que, en general, no tiene sentido preocuparse por este nivel de optimización.

Si está utilizando un compilador para un sistema integrado y sabe que no puede manejar este tipo de optimización simple (o no tiene una biblioteca estándar), use la versión de estuche especial codificada a mano.

Si está codificando normalmente, use la versión más legible (imho que puede ser strcmp o strlen o [0] == 0 según el contexto).

Si está escribiendo un código altamente eficiente, espera que lo llamen miles o millones de veces por segundo, (a) prueba que es en realidad más eficiente y (b) si la versión legible es demasiado lenta, intente escribir algo que compile mejor montaje

Con 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

Con 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] Aunque tenga cuidado, en casos más complicados que una prueba directa contra cero, la biblioteca y el código del compilador normalmente serán mejores que los códigos hechos a mano.


El acceso a una matriz es orden 1 en tiempo de ejecución, por lo tanto, es más rápido que la función.


Es evidente que va a ser más rápido, y probablemente valga la pena colocar su propio código en una función en línea, o incluso en una macro, si planea seguir adelante con él:

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

y deja que el compilador optimice eso para ti. En cualquier caso, strcmp necesita finalmente verificar ''/0'' para que siempre seas al menos igual. (honestamente, probablemente dejaría que el compilador optimice el uso compartido interno de lo anterior, por ejemplo, isEmpty probablemente solo voltee isNotEmpty )


Esto es tan micro-optimizante como es posible, pero supongo que si agrega una comprobación nula antes de indexar foo (a menos que sepa que nunca será nula) técnicamente ahorraría la sobrecarga de una llamada de función.


No veo ninguna ventaja de usar strcmp en este caso. El compilador puede ser lo suficientemente inteligente como para optimizarlo, pero no será más rápido que verificar el byte ''/ 0'' directamente. El implementador de esto podría haber elegido este constructo porque pensó que es más legible, pero creo que esto es una cuestión de gusto en este caso. Aunque escribiría el cheque un poco diferente ya que este es el idioma que parece ser usado más a menudo para buscar una cadena vacía:

if( !*str )

y

if( *str )

para comprobar si hay una cadena no vacía.


Tienes razón: ya que al llamar a strcmp() agrega la administración de la pila y el salto de memoria a las instrucciones reales de strcmp, obtendrás algunas instrucciones con solo revisar el primer byte de tu cadena.

Para su curiosidad, puede revisar el código de strcmp () aquí: http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcmp.c;h=bd53c05c6e21130b091bd75c3fc93872dd71fe4b;hb=HEAD

(Pensé que el código se llenaría con #ifdef y oscuro __GNUSOMETHING , ¡pero en realidad es bastante simple!)


Un buen compilador de optimización podría optimizar la llamada a la función y luego eliminar el bucle de la función en línea. No hay forma de que su método sea más lento, aunque existe la posibilidad de que sea la misma velocidad.


strcmp () es una llamada de función y, por lo tanto, tiene una sobrecarga de llamada de función. foo [0] es el acceso directo a la matriz, por lo que es obviamente más rápido.