2009-09-08 24 views
10

A veces es necesario comparar la longitud de una cuerda con una constante.
Por ejemplo:¿Es eficaz el tiempo de compilación "strlen()"?

if (line.length() > 2) 
{ 
    // Do something... 
} 

Pero estoy tratando de evitar el uso de constantes "mágicas" en el código.
Por lo general utilizan dicho código:

if (line.length() > strlen("[]")) 
{ 
    // Do something... 
} 

Es más fácil de leer, pero no es eficiente debido a la llamada a la función.
escribí funciones de la plantilla de la siguiente manera:

template<size_t N> 
size_t _lenof(const char (&)[N]) 
{ 
    return N - 1; 
} 

template<size_t N> 
size_t _lenof(const wchar_t (&)[N]) 
{ 
    return N - 1; 
} 

// Using: 
if (line.length() > _lenof("[]")) 
{ 
    // Do something... 
} 

En una versión de lanzamiento (VisualStudio 2008) que produce bastante bueno código:

cmp dword ptr [esp+27Ch],2 
jbe 011D7FA5 

Y lo bueno es que el compilador no incluye la "[]" cadena en la salida binaria.

¿Es una optimización específica del compilador o es un comportamiento común?

+2

es probable que pueda usar una plantilla para todos los tipos de matriz, algo mienta esto: 'plantilla tamaño_t _lenof (const T (&) [N]) {return N - 1; } ', debería funcionar igual que en tu ejemplo. –

+2

@Evan Teran: buena idea, pero estas funciones solo tienen sentido para las cadenas (matriz de char/wchar_t) debido a la terminación '\ 0'. Su función funcionará para int [10] y devolverá 9 - No creo que tenga sentido;) – Dmitriy

+0

@Dmitriy: de hecho –

Respuesta

4

La capacidad de alinear una llamada a función es tanto una optimización del compilador y un comportamiento común. Es decir, muchos compiladores pueden hacerlo, pero no están obligados a hacerlo.

+0

La optimización deseada no requiere (solo) inlineación. Requiere que la longitud de la cadena se compute en tiempo de compilación. –

+0

Eso no es realmente una optimización, sin embargo. La longitud no se computaría en tiempo de ejecución y aún llamaría a cualquier función '_lenof'. ¿El estándar * requiere * implementaciones para dar a los literales de cadena el tipo 'const char [N]'? ¿Y no se requieren valores de ese tipo para hacer que el compilador deduzca los argumentos de la función de plantilla para ser 'N'? –

+0

Disculpa, no entendí a qué se refería tu respuesta, por alguna razón, pensé que hablabas de que "no era eficiente debido a la llamada de función [del strlen]". Si un compilador no puede alinear _lenof, entonces probablemente no pueda alinear nada, y sería un compilador de C++ bastante pobre en general. Cualquier uso serio de plantillas sería una pesadilla ... –

12

Por qué no

 
sizeof "[]" - 1; 

(menos uno para la hipótesis nula de arrastre Se podría hacer sizeof "[]" -. Sizeof '\ 0', pero sizeof '\ 0' es a menudo sizeof (int) en C, y "- 1" es perfectamente legible )

+0

no funcionaría para cadenas anchas (por ejemplo, L "[]"). – Dmitriy

+1

podría ser arreglado para cadenas anchas. Algo así como: '(sizeof (L" [] ")/sizeof (L" ")) - 1' –

+0

@Evan Teran: sí, pero debería usar macros para hacerlo más legible. Mis macros en mi humilde opinión es más estilo C pero no C++ – Dmitriy

-7
#define TWO 2 
#define STRING_LENGTH 2 
/* ... etc ... */ 

en serio, ¿por qué pasar por todo esto sin problemas sólo para evitar escribir un 2.? Honestamente creo que estás haciendo que tu código sea menos legible, y otros programadores te mirarán como si estuvieras inhalando el café usado del filtro.

+0

es solo un ejemplo. En código real, parece "una cadena". ¿Vas a contar la cantidad de caracteres en este caso? :) – Dmitriy

+0

Sí, lo soy. Y lo haré. Y lo hago –

+2

@Jed Smith: :) ¿Estás seguro de que no olvides cambiar la definición de la macro si la cadena cambia? – Dmitriy

2

Creo que la mayoría de los compiladores lo optimizarán cuando las optimizaciones estén habilitadas. Si están deshabilitados, puede ralentizar su programa mucho más de lo necesario.

Preferiría sus funciones de plantilla, ya que están garantizadas para no llamar al strlen en tiempo de ejecución. Por supuesto, en lugar de escribir funciones separadas para char y wchar_t, se podría añadir otro argumento plantilla, y obtener una función que funciona para cualquier tipo:

template <typename Char_t, int len> 
int static_strlen(const Char_t (&)[N] array){ 
    return len/sizeof(Char_t) - 1; 
} 

(Como ya se ha mencionado en los comentarios, esto dará resultados divertidos si se aprueba una matriz de enteros, pero es probable que se hacer eso? está destinado para cuerdas, después de todo)

una nota final, el nombre _strlen es mala . Todos los nombres en el ámbito del espacio de nombres que comienzan con un guión bajo están reservados para la implementación. Arriesgas algunos desagradables conflictos de nombres.

Por cierto, ¿por qué es "[]" una constante menos mágica que 2?

En ambos casos, es un literal que debe cambiarse si cambia el formato de la cadena en la que se compara.

+0

Por alguna razón, su función no parece ser más rápida que usar strlen. Sin embargo, parece ser más rápido que usar std :: char_traits :: length, por lo que sigue siendo útil ya que strlen solo funciona en arreglos de caracteres. – leetNightshade

Cuestiones relacionadas