+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 = bd53c05c6e21130b091bd75c3fc93872dd71fe4b; hb = HEAD)!
Tiene la certeza de que strcmp nunca puede ser más rápido que una comparación directa [1], pero la pregunta es, ¿el compilador lo optimizará? Me intimidaba intentar medir eso, pero me sorprendió gratamente lo fácil que era. Mi código de ejemplo es (omitiendo los encabezados):
bool isEmpty(char * str) {
return 0==std::strcmp(str,"");
}
bool isEmpty2(char * str) {
return str[0]==0;
}
y yo tratamos de compilar que, en primer lugar con gcc -S -o- emptystrcmptest.cc
y luego con gcc -S -O2 -o- emptystrcmptest.cc
. Para mi agradable sorpresa, aunque no puedo leer muy bien el ensamblaje, la versión no optimizada mostró claramente una diferencia, y la versión optimizada mostró claramente que las dos funciones tenían un ensamblaje idéntico.
Por lo tanto, yo 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 maneja este tipo de optimización simple (o no tiene una biblioteca estándar), use la versión de caso especial codificada a mano.
Si está codificando normalmente, use la versión más legible (lo que puede ser strcmp o strlen o [0] == 0 según el contexto).
Si está escribiendo código altamente eficiente, espera que lo llamen miles o millones de veces por segundo, (a) prueba que es realmente más eficiente y (b) si la versión legible es muy lenta, intente escribir algo que se compilará para un mejor ensamblaje.
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] A pesar de tener cuidado - en los casos más complicados que una prueba directa contra cero, la biblioteca y el código de compilador de una típicamente SERÁ mejor que el código hecho a mano.
Tienes razón para cuestionar el patrón, y me gusta más tu forma de hacerlo. – SingleNegationElimination
Al verificar la cadena vacía, tiene más sentido para mí hacer 'if (strlen (foo) == 0)'. –
@Jamie Wong: si la cadena tiene 1Meg de longitud, entonces debe verificar 1 millón de bytes antes de encontrar el nulo de terminación; Esta es una pérdida bastante grande cuando solo está interesado en el caso en que la cadena tiene cero o más de cero caracteres. – SingleNegationElimination