Вопрос на собеседовании: какой из них будет выполняться быстрее if (flag==0)или if (0==flag)? Зачем?
if(flag = 0)ценой небольшой читабельности.
Вопрос на собеседовании: какой из них будет выполняться быстрее if (flag==0)или if (0==flag)? Зачем?
if(flag = 0)ценой небольшой читабельности.
Ответы:
Я еще не видел правильного ответа (а некоторые уже есть). Предупреждение: Nawaz указал на определяемую пользователем ловушку . И я сожалею о том, что поспешно проголосовал за "самый глупый вопрос", потому что, похоже, многие не поняли его правильно, и это дает место для приятного обсуждения оптимизации компилятора :)
Ответ:
Какой
flagтип?
В том случае, если это flagдействительно пользовательский тип. Тогда это зависит от того, какая перегрузка operator==выбрана. Конечно, может показаться глупым, что они не будут симметричными, но это, безусловно, разрешено, и я уже видел другие нарушения.
Если flagэто встроенный, то оба должны иметь одинаковую скорость.
Из статьи Википедии о x86, я бы поставил на Jxxинструкцию для ifзаявления: возможно, JNZ(переход , если не ноль) или некоторый эквивалент.
Сомневаюсь, что компилятор пропустит такую очевидную оптимизацию даже при отключенной оптимизации. Это тот тип вещей, для которого предназначена Peephole Optimization .
EDIT: снова возник, поэтому давайте добавим некоторую сборку (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
}
Даже если кто-то не умеет читать IR, я думаю, что это говорит само за себя.
flagдолжно быть целое или логическое значение. OTOH, наличие переменной с именем flagопределяемого пользователем типа совершенно неправильно само по себе, ИМХО
#includeдирективы. Для простоты обычно составляетint , char, boolи тому подобное. Все остальные типы называются определенные пользователем, то есть они существуют , потому что они являются результатом какого - то пользователя объявляющего их: typedef, enum, struct, class. Например, std::stringопределяется пользователем, хотя вы, конечно, не определили его сами :)
Тот же код для amd64 с 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
В ваших версиях разницы не будет.
Я предполагаю, что typeфлаг of не является определяемым пользователем типом, а скорее является встроенным типом. Enum - исключение! . Вы можете относиться к перечислению как к встроенному. Фактически, значения it - это один из встроенных типов!
В случае, если это определяемый пользователем тип (кроме enum), то ответ полностью зависит от того, как вы перегрузили оператор ==. Обратите внимание, что вам нужно перегрузить ==, определив две функции, по одной для каждой из ваших версий!
Абсолютно никакой разницы.
Вы можете получить очки, отвечая на этот вопрос собеседования, сославшись на устранение опечаток при назначении / сравнении:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
Хотя верно то, что, например, C-компилятор предупреждает в случае первого ( flag = 0), таких предупреждений нет в PHP, Perl или Javascript или <insert language here>.
По скорости абсолютно никакой разницы не будет. Почему должно быть?
x == 0можно использовать ее, но 0 == xможно использовать обычное сравнение. Я действительно сказал, что его нужно будет отложить.
virtual operator==(int)пользовательский тип?
Ну, есть разница, когда флаг является определяемым пользователем типом
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;
}
}
В первом случае (0 == s) вызывается оператор преобразования, а затем возвращаемый результат сравнивается с 0. Во втором случае вызывается оператор ==.
Если сомневаетесь, сравните его и узнайте правду.
Они должны быть точно такими же по скорости.
Обратите внимание, однако, что некоторые люди помещают константу слева при сравнении равенства (так называемые «условия Йоды»), чтобы избежать всех ошибок, которые могут возникнуть, если вы напишете =(оператор присваивания) вместо ==(оператор сравнения равенства); поскольку присвоение литералу вызывает ошибку компиляции, ошибки такого рода можно избежать.
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
{
}
С другой стороны, большинство людей находят «условные выражения Йоды» странно выглядящими и раздражающими, особенно потому, что класс ошибок, которые они предотвращают, можно определить также с помощью соответствующих предупреждений компилятора.
if(flag=0) // <--- warning: assignment in conditional expression
{
}
Как говорили другие, разницы нет.
0 должен быть оценен. flagдолжен быть оценен. Этот процесс занимает одинаковое время, независимо от того, с какой стороны они расположены.
Правильный ответ: у них одинаковая скорость.
Даже выражения if(flag==0)и if(0==flag)имеют одинаковое количество символов! Если бы один из них был написан какif(flag== 0) , тогда у компилятора было бы одно дополнительное пространство для синтаксического анализа, так что у вас была бы законная причина указать время компиляции.
Но поскольку такого нет, нет абсолютно никаких причин, по которым один должен быть быстрее другого. Если есть причина, то компилятор делает очень и очень странные вещи с сгенерированным кодом ...
Какой из них быстрый, зависит от того, какую версию == вы используете. Вот фрагмент, в котором используются 2 возможные реализации ==, и в зависимости от того, выберете ли вы вызов x == 0 или 0 == x, будет выбран один из 2 вариантов.
Если вы просто используете POD, это не имеет значения, когда дело касается скорости.
#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);
}
Что ж, я полностью согласен со всем, что сказано в комментариях к OP, ради упражнения:
Если компилятор недостаточно умен (действительно, вы не должны его использовать) или оптимизация отключена, x == 0можно скомпилировать в собственную jump if zeroинструкцию сборки , в то время как0 == x может быть более общее (и дорогостоящее) сравнение числовых значений.
Тем не менее, я бы не хотел работать на начальника, который думает так ...
Конечно же, нет разницы в скорости исполнения. Состояние необходимо оценивать в обоих случаях одинаково.
Думаю, лучший ответ - «на каком языке этот пример»?
В вопросе не указан язык, и он помечен как «C», так и «C ++». Для точного ответа требуется дополнительная информация.
Это паршивый вопрос программирования, но он мог бы быть хорошим для хитрого отдела «давайте дадим интервьюируемому достаточно веревки, чтобы он повесился или построил качели для дерева». Проблема с такими вопросами в том, что они обычно записываются и передаются от интервьюера к интервьюеру, пока не дойдут до людей, которые действительно не понимают его со всех сторон.
Постройте две простые программы, используя предложенные способы.
Соберите коды. Посмотри на сборку и можешь судить, но я сомневаюсь, что есть разница!
Интервью становится все меньше, чем когда-либо.
В качестве отступления (я действительно думаю, что любой достойный компилятор сделает этот вопрос спорным, поскольку он оптимизирует его), использование флага 0 == вместо флага == 0 предотвращает опечатку, когда вы забываете один из = (т.е. если вы случайно набираете flag = 0 он будет компилироваться, но 0 = flag не будет), что я считаю ошибкой, которую каждый совершал в тот или иной момент ...