2009-09-08 21 views
10

A volte è necessario confrontare la lunghezza di una stringa con una costante.
Per esempio:È valido "strlen()" in fase di compilazione?

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

Ma sto cercando di evitare l'uso di costanti "magici" nel codice.
solito utilizzare tale codice:

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

è più leggibile, ma non efficiente a causa della chiamata di funzione.
Ho scritto funzioni template come segue:

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

In una build di rilascio (VisualStudio 2008) produce codice abbastanza buono:

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

E la cosa buona è che il compilatore non include il "[]" stringa nell'output binario.

È un ottimizzazione specifica del compilatore o è un comportamento comune?

+2

probabilmente si potrebbe utilizzare un modello per tutti i tipi di array, qualcosa di mentire in questo modo: 'template size_t _lenof (const T (e) [N]) {return N - 1; } ', dovrebbe funzionare come il tuo esempio. –

+2

@Evan Teran: buona idea, ma queste funzioni hanno senso solo per le stringhe (array di char/wchar_t) a causa della terminazione di '\ 0'. La tua funzione funzionerà per int [10] e restituirà 9 - Non penso che abbia senso;) – Dmitriy

+0

@Dmitriy: anzi –

risposta

4

La capacità di inline di una chiamata di funzione è sia l'ottimizzazione specifica del compilatore e un comportamento comune. Cioè, molti compilatori possono farlo, ma non sono obbligati a farlo.

+0

L'ottimizzazione desiderato non (solo) richiedono inline. Richiede che la lunghezza della stringa sia calcolata in fase di compilazione. –

+0

Tuttavia, non è proprio un'ottimizzazione. La lunghezza non viene calcolata in fase di esecuzione e viene comunque chiamata qualsiasi funzione '_lenof'. Non lo standard * richiede * implementazioni per dare stringhe letterali il tipo 'const char [N]'? E non sono necessari valori di questo tipo per fare in modo che il compilatore deduca gli argomenti della funzione template come 'N'? –

+0

Mi spiace, ho frainteso a cosa si riferiva la tua risposta, per qualche motivo, anche se stavi parlando di "non efficiente a causa della chiamata di funzione [strlen]". Se un compilatore non può inline _lenof, allora probabilmente non può inline nulla e sarebbe un compilatore C++ piuttosto scarso in generale. Qualsiasi uso serio di modelli sarebbe da incubo ... –

12

Perché non

 
sizeof "[]" - 1; 

(meno uno per il nulla di trascinamento Si potrebbe fare sizeof "[]" -. Sizeof '\ 0', ma sizeof '\ 0' è spesso sizeof (int) in C, e "- 1" è perfettamente leggibile)

+0

non funzionerebbe con le stringhe ampie (ad esempio, L "[]"). – Dmitriy

+1

potrebbe essere risolto per stringhe larghe. Qualcosa come: '(sizeof (L" [] ")/sizeof (L" ")) - 1' –

+0

@Evan Teran: sì, ma è necessario utilizzare macro per renderlo più leggibile. I macro IMHO sono più in stile C ma non in C++ – Dmitriy

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

Scherzi a parte, perché passare attraverso tutto questo fastidio solo per evitare digitando un 2.? Onestamente penso che stai rendendo il tuo codice meno leggibile, e altri programmatori ti fisseranno come se stessi sniffando il caffè usato dal filtro.

+0

è solo un esempio. Nel codice reale sembra "una corda". Hai intenzione di contare il numero di personaggi in questo caso? :) – Dmitriy

+0

Sì, lo sono. E lo farò. E io faccio. –

+2

@Jed Smith: :) Sei sicuro di non dimenticare di cambiare la definizione della macro se la stringa cambia? – Dmitriy

2

Penso che molti compilatori lo ottimizzeranno via quando le ottimizzazioni sono abilitate. Se sono disabilitati, potrebbe rallentare il programma molto più del necessario.

Preferirei le funzioni del modello, poiché sono garantite per non chiamare strlen in fase di esecuzione. Naturalmente, piuttosto che scrivere funzioni separate per char e wchar_t, si potrebbe aggiungere un altro argomento di un template, e ottenere una funzione che funziona per qualsiasi tipo:

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

(Come già accennato nei commenti, questo darà risultati divertenti se si passa un array di int, ma siete suscettibili di farlo? E 'pensato per le stringhe, dopo tutto)

una nota finale, il nome _strlen è male. Tutti i nomi nello spazio dei nomi che iniziano con un carattere di sottolineatura sono riservati all'implementazione. Rischia alcuni brutti conflitti di denominazione.

A proposito, perché "[]" meno di una costante magica di 2 è?

In entrambi i casi, è un letterale che deve essere cambiato se il formato della stringa è confrontato ai cambiamenti.

+0

Per qualsiasi motivo, la tua funzione non sembra essere più veloce dell'utilizzo di strlen. Tuttavia, sembra essere più veloce rispetto all'utilizzo di std :: char_traits :: length, quindi è comunque utile poiché strlen funziona solo su array di caratteri. – leetNightshade

Problemi correlati