Pergunta da entrevista: Qual deles vai executar mais rápido if (flag==0)
ou if (0==flag)
? Por quê?
if(flag = 0)
ao preço de um pouco de legibilidade.
Pergunta da entrevista: Qual deles vai executar mais rápido if (flag==0)
ou if (0==flag)
? Por quê?
if(flag = 0)
ao preço de um pouco de legibilidade.
Respostas:
Ainda não vi nenhuma resposta correta (e já existem algumas) ressalva: Nawaz apontou a armadilha definida pelo usuário . E eu me arrependo de ter votado apressadamente na "pergunta mais estúpida" porque parece que muitos não acertaram e isso dá espaço para uma boa discussão sobre a otimização do compilador :)
A resposta é:
Qual é
flag
o tipo de?
No caso em que flag
realmente é um tipo definido pelo usuário. Então, depende de qual sobrecarga operator==
está selecionada. Claro que pode parecer estúpido que eles não sejam simétricos, mas certamente é permitido, e eu já vi outros abusos.
Se flag
for embutido, ambos deverão ter a mesma velocidade.
A partir do artigo da Wikipédia em x86
, eu apostaria para uma Jxx
instrução para a if
declaração: talvez um JNZ
(Salte Se não for Zero) ou algum equivalente.
Eu duvido que o compilador perca uma otimização tão óbvia, mesmo com otimizações desativadas. Este é o tipo de coisa para a qual o Peephole Optimization foi projetado.
EDIT: Sprang up novamente, então vamos adicionar um pouco de montagem (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
}
Mesmo que a pessoa não saiba ler o RI, acho que é autoexplicativo.
flag
deve ser inteiro ou booleano. OTOH, ter uma variável chamada flag
de um tipo definido pelo usuário é bastante errado em si mesmo, IMHO
#include
diretiva. Para simplificar, que normalmente equivale a int
, char
, bool
e similares. Todos os outros tipos são disse a ser definida pelo usuário, que é que eles existem, porque eles são o resultado de algum usuário declarando-os: typedef
, enum
, struct
, class
. Por exemplo, std::string
é definido pelo usuário, embora você certamente não o tenha definido :)
Mesmo código para amd64 com 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
Não haverá diferença em suas versões.
Estou assumindo que o type
sinalizador de não é um tipo definido pelo usuário, mas sim algum tipo integrado. Enum é exceção! . Você pode tratar enum como se estivesse embutido. Na verdade, seus valores são de um tipo embutido!
No caso, se for do tipo definido pelo usuário (exceto enum
), então a resposta depende inteiramente de como você sobrecarregou o operador ==
. Observe que você deve sobrecarregar ==
definindo duas funções, uma para cada uma de suas versões!
Não há absolutamente nenhuma diferença.
Você pode ganhar pontos ao responder a essa pergunta da entrevista, referindo-se à eliminação de erros de atribuição / comparação, embora:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
Embora seja verdade, que, por exemplo, um compilador C avisa no caso do anterior ( flag = 0
), não existem tais avisos em PHP, Perl ou Javascript ou <insert language here>
.
Não haverá absolutamente nenhuma diferença em termos de velocidade. Por que deveria haver?
x == 0
pode ser usado, mas 0 == x
pode usar uma comparação normal. Eu disse que teria que ser retardado.
virtual operator==(int)
em um tipo definido pelo usuário?
Bem, há uma diferença quando o sinalizador é um tipo definido pelo usuário
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;
}
}
No primeiro caso (0 == s), o operador de conversão é chamado e, em seguida, o resultado retornado é comparado a 0. No segundo caso, o operador == é chamado.
Em caso de dúvida, faça um benchmark e aprenda a verdade.
Eles devem ser exatamente os mesmos em termos de velocidade.
Observe, entretanto, que algumas pessoas costumam colocar a constante à esquerda em comparações de igualdade (os chamados "condicionais de Yoda") para evitar todos os erros que podem surgir se você escrever =
(operador de atribuição) em vez de ==
(operador de comparação de igualdade); uma vez que a atribuição a um literal aciona um erro de compilação, esse tipo de erro é evitado.
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
{
}
Por outro lado, a maioria das pessoas acha as "condicionais do Yoda" estranhas e irritantes, especialmente porque a classe de erros que elas evitam também pode ser detectada usando avisos do compilador adequados.
if(flag=0) // <--- warning: assignment in conditional expression
{
}
Como outros já disseram, não há diferença.
0
tem que ser avaliado. flag
tem que ser avaliado. Esse processo leva o mesmo tempo, não importa de que lado estão colocados.
A resposta certa seria: ambos têm a mesma velocidade.
Mesmo as expressões if(flag==0)
e if(0==flag)
têm a mesma quantidade de caracteres! Se um deles foi escrito como if(flag== 0)
, o compilador teria um espaço extra para analisar, então você teria um motivo legítimo para apontar o tempo de compilação.
Mas, como não existe tal coisa, não há absolutamente nenhuma razão para que um seja mais rápido do que o outro. Se houver um motivo, o compilador está fazendo coisas muito, muito estranhas no código gerado ...
Qual é o mais rápido depende de qual versão de == você está usando. Aqui está um snippet que usa 2 implementações possíveis de == e, dependendo se você escolhe chamar x == 0 ou 0 == x, um dos 2 é selecionado.
Se você estiver usando apenas um POD, isso realmente não deve importar quando se trata de velocidade.
#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);
}
Bem, estou concordando totalmente com tudo o que foi dito nos comentários ao OP, para fins de exercício:
Se o compilador não for inteligente o suficiente (na verdade, você não deve usá-lo) ou a otimização estiver desabilitada, x == 0
pode compilar para uma jump if zero
instrução de montagem nativa , enquanto 0 == x
poderia ser uma comparação mais genérica (e cara) de valores numéricos.
Ainda assim, não gostaria de trabalhar para um chefe que pensa nestes termos ...
Certamente nenhuma diferença em termos de velocidade de execução. A condição deve ser avaliada em ambos os casos da mesma maneira.
Acho que a melhor resposta é "em que idioma está esse exemplo"?
A pergunta não especifica o idioma e está marcada com 'C' e 'C ++'. Uma resposta precisa precisa de mais informações.
É uma péssima pergunta de programação, mas poderia ser uma boa no tortuoso departamento "vamos dar ao entrevistado corda suficiente para se enforcar ou construir um balanço de árvore". O problema com esse tipo de pergunta é que geralmente são escritas e passadas de entrevistador para entrevistador, até chegar a pessoas que não as entendem de todos os ângulos.
Construa dois programas simples usando as maneiras sugeridas.
Reúna os códigos. Olhe a assembléia e você pode julgar, mas duvido que haja diferença!
As entrevistas estão ficando mais baixas do que nunca.
Apenas como um aparte (eu realmente acho que qualquer compilador decente tornará esta questão discutível, uma vez que irá otimizá-la) usando 0 == sinalizador sobre sinalizador == 0 evita o erro de digitação onde você esquece um dos = (ou seja, se você digitar acidentalmente flag = 0 ele irá compilar, mas 0 = flag não), o que eu acho que é um erro que todos cometeram em um ponto ou outro ...