Domanda dell'intervista: quale verrà eseguita più velocemente if (flag==0)
o if (0==flag)
? Perché?
if(flag = 0)
al prezzo di un po 'di leggibilità.
Domanda dell'intervista: quale verrà eseguita più velocemente if (flag==0)
o if (0==flag)
? Perché?
if(flag = 0)
al prezzo di un po 'di leggibilità.
Risposte:
Non ho ancora visto alcuna risposta corretta (e ce ne sono già alcune) avvertenza: Nawaz ha sottolineato la trappola definita dall'utente . E mi dispiace di aver votato frettolosamente alla "domanda più stupida" perché sembra che molti non abbiano capito bene e dà spazio per una bella discussione sull'ottimizzazione del compilatore :)
La risposta è:
Qual è
flag
il tipo di?
Nel caso in cui flag
effettivamente sia un tipo definito dall'utente. Quindi dipende da quale sovraccarico operator==
è selezionato. Ovviamente può sembrare stupido che non siano simmetriche, ma è certamente permesso, e ho già visto altri abusi.
Se flag
è un built-in, allora entrambi dovrebbero prendere la stessa velocità.
Dalla articolo di Wikipedia su x86
, scommetterei di Jxx
istruzione per l' if
affermazione: forse un JNZ
(Vai se non nullo) o qualche equivalente.
Dubito che il compilatore manchi un'ottimizzazione così ovvia, anche con le ottimizzazioni disattivate. Questo è il tipo di cose per cui è progettata l' ottimizzazione dello spioncino .
EDIT: Sprang up di nuovo, quindi aggiungiamo un po 'di assembly (LLVM 2.7 IR)
int regular(int c) {
if (c == 0) { return 0; }
return 1;
}
int yoda(int c) {
if (0 == c) { return 0; }
return 1;
}
define i32 @regular(i32 %c) nounwind readnone {
entry:
%not. = icmp ne i32 %c, 0 ; <i1> [#uses=1]
%.0 = zext i1 %not. to i32 ; <i32> [#uses=1]
ret i32 %.0
}
define i32 @yoda(i32 %c) nounwind readnone {
entry:
%not. = icmp ne i32 %c, 0 ; <i1> [#uses=1]
%.0 = zext i1 %not. to i32 ; <i32> [#uses=1]
ret i32 %.0
}
Anche se non si sa leggere l'IR, penso che si spieghi da sé.
flag
debba essere un numero intero o booleano. OTOH, avere una variabile denominata flag
di un tipo definito dall'utente è abbastanza sbagliato di per sé, IMHO
#include
direttiva. Per ragioni di semplicità, di solito è pari a int
, char
, bool
e simili. Tutti gli altri tipi sono detti essere definite dall'utente, cioè esistono perché sono il risultato di qualche utente dichiarando: typedef
, enum
, struct
, class
. Ad esempio, std::string
è definito dall'utente, anche se di certo non lo hai definito tu stesso :)
Stesso codice per amd64 con GCC 4.1.2:
.loc 1 4 0 # int f = argc;
movl -20(%rbp), %eax
movl %eax, -4(%rbp)
.loc 1 6 0 # if( f == 0 ) {
cmpl $0, -4(%rbp)
jne .L2
.loc 1 7 0 # return 0;
movl $0, -36(%rbp)
jmp .L4
.loc 1 8 0 # }
.L2:
.loc 1 10 0 # if( 0 == f ) {
cmpl $0, -4(%rbp)
jne .L5
.loc 1 11 0 # return 1;
movl $1, -36(%rbp)
jmp .L4
.loc 1 12 0 # }
.L5:
.loc 1 14 0 # return 2;
movl $2, -36(%rbp)
.L4:
movl -36(%rbp), %eax
.loc 1 15 0 # }
leave
ret
Non ci saranno differenze nelle tue versioni.
Presumo che il type
flag of non sia un tipo definito dall'utente, piuttosto è un tipo predefinito. Enum è un'eccezione! . Puoi trattare enum come se fosse integrato. In effetti, i valori sono uno dei tipi incorporati!
Nel caso in cui, se è un tipo definito dall'utente (eccetto enum
), la risposta dipende interamente da come hai sovraccaricato l'operatore ==
. Nota che devi sovraccaricare ==
definendo due funzioni, una per ciascuna delle tue versioni!
Non c'è assolutamente alcuna differenza.
Potresti guadagnare punti rispondendo a quella domanda dell'intervista facendo riferimento all'eliminazione degli errori di battitura di assegnazione / confronto, tuttavia:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
Anche se è vero, che ad esempio un compilatore C avverte nel caso del primo ( flag = 0
), non ci sono tali avvisi in PHP, Perl o Javascript o <insert language here>
.
Non ci sarà assolutamente alcuna differenza in termini di velocità. Perché dovrebbe esserci?
x == 0
potrebbe essere utilizzata ma 0 == x
potrebbe utilizzare un confronto normale. Ho detto che avrebbe dovuto essere ritardato.
virtual operator==(int)
in un tipo definito dall'utente?
Ebbene, c'è una differenza quando flag è un tipo definito dall'utente
struct sInt
{
sInt( int i ) : wrappedInt(i)
{
std::cout << "ctor called" << std::endl;
}
operator int()
{
std::cout << "operator int()" << std::endl;
return wrappedInt;
}
bool operator==(int nComp)
{
std::cout << "bool operator==(int nComp)" << std::endl;
return (nComp == wrappedInt);
}
int wrappedInt;
};
int
_tmain(int argc, _TCHAR* argv[])
{
sInt s(0);
//in this case this will probably be faster
if ( 0 == s )
{
std::cout << "equal" << std::endl;
}
if ( s == 0 )
{
std::cout << "equal" << std::endl;
}
}
Nel primo caso (0 == s) viene chiamato l'operatore di conversione e quindi il risultato restituito viene confrontato con 0. Nel secondo caso viene chiamato l'operatore ==.
In caso di dubbio, valutalo e impara la verità.
Dovrebbero essere esattamente gli stessi in termini di velocità.
Si noti tuttavia che alcune persone usano per mettere la costante a sinistra nei confronti di uguaglianza (i cosiddetti "condizionali di Yoda") per evitare tutti gli errori che possono sorgere se si scrive =
(operatore di assegnazione) invece di ==
(operatore di confronto di uguaglianza); poiché l'assegnazione a un letterale innesca un errore di compilazione, questo tipo di errore viene evitato.
if(flag=0) // <--- typo: = instead of ==; flag is now set to 0
{
// this is never executed
}
if(0=flag) // <--- compiler error, cannot assign value to literal
{
}
D'altra parte, la maggior parte delle persone trova i "condizionali di Yoda" strani e fastidiosi, soprattutto perché la classe di errori che prevengono può essere individuata anche utilizzando adeguati avvisi del compilatore.
if(flag=0) // <--- warning: assignment in conditional expression
{
}
Come altri hanno già detto, non c'è differenza.
0
deve essere valutato. flag
deve essere valutato. Questo processo richiede lo stesso tempo, indipendentemente da quale lato siano posizionati.
La risposta giusta sarebbe: hanno entrambe la stessa velocità.
Anche le espressioni if(flag==0)
e if(0==flag)
hanno la stessa quantità di caratteri! Se uno di essi è stato scritto come if(flag== 0)
, il compilatore avrebbe uno spazio in più da analizzare, quindi avresti una ragione legittima per indicare il tempo di compilazione.
Ma poiché non esiste una cosa del genere, non c'è assolutamente alcun motivo per cui uno dovrebbe essere più veloce di un altro. Se c'è un motivo, il compilatore sta facendo cose molto, molto strane per il codice generato ...
Quale è veloce dipende dalla versione di == che stai usando. Ecco uno snippet che utilizza 2 possibili implementazioni di == e, a seconda che si scelga di chiamare x == 0 o 0 == x, viene selezionata una delle 2.
Se stai usando solo un POD, questo non dovrebbe avere importanza quando si tratta di velocità.
#include <iostream>
using namespace std;
class x {
public:
bool operator==(int x) { cout << "hello\n"; return 0; }
friend bool operator==(int x, const x& a) { cout << "world\n"; return 0; }
};
int main()
{
x x1;
//int m = 0;
int k = (x1 == 0);
int j = (0 == x1);
}
Bene, sono completamente d'accordo con tutto ciò che è stato detto nei commenti all'OP, per il bene dell'esercizio:
Se il compilatore non è abbastanza intelligente (anzi non dovresti usarlo) o l'ottimizzazione è disabilitata, x == 0
potrebbe essere compilato in jump if zero
un'istruzione assembly nativa , mentre 0 == x
potrebbe essere un confronto più generico (e costoso) di valori numerici.
Tuttavia, non mi piacerebbe lavorare per un capo che pensa in questi termini ...
Sicuramente nessuna differenza in termini di velocità di esecuzione. La condizione deve essere valutata in entrambi i casi allo stesso modo.
Penso che la risposta migliore sia "in che lingua è questo esempio"?
La domanda non specificava la lingua ed è contrassegnata sia con "C" che con "C ++". Una risposta precisa necessita di maggiori informazioni.
È una pessima domanda di programmazione, ma potrebbe essere una buona cosa nel reparto ambiguo "diamo all'intervistato abbastanza corda per impiccarsi o costruire un'altalena". Il problema con questo tipo di domande è che di solito vengono scritte e tramandate da intervistatore a intervistatore fino a quando non arrivano a persone che non le capiscono davvero da tutte le angolazioni.
Costruisci due semplici programmi usando i modi suggeriti.
Assembla i codici. Guarda l'assemblea e puoi giudicare, ma dubito che ci sia una differenza!
Le interviste stanno diventando più basse che mai.
Per inciso (in realtà penso che qualsiasi compilatore decente renderà discutibile questa domanda, dal momento che la ottimizzerà) usando 0 == flag over flag == 0 impedisce l'errore di battitura in cui dimentichi uno dei = (cioè se digiti accidentalmente flag = 0 verrà compilato, ma 0 = flag no), che penso sia un errore che tutti hanno fatto in un punto o in un altro ...