Питання для інтерв'ю: хто з них виконає швидше, 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
}
Навіть якщо хтось не знає, як читати ІЧ, я вважаю, що це пояснює себе.
flagповинні бути цілими чи булевими. OTOH, що має змінну з іменем flagвизначеного користувачем типу, зовсім не так, IMHO
#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прапор - це не визначений користувачем тип, скоріше це якийсь вбудований тип. Енум - виняток! . Ви можете ставитися до перегною, ніби вбудована. Насправді це значення є одним із вбудованих типів!
У випадку, якщо це визначений користувачем тип (крім 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 == с) викликається оператор перетворення, а потім повертається результат порівнюється з 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);
}
Ну, я повністю згоден з усім, що було сказано в коментарях до ОП, заради вправ:
Якщо компілятор недостатньо розумний (дійсно, ви не повинні його використовувати) або оптимізація вимкнена, x == 0можна було б компілювати до власної jump if zeroінструкції збірки , тоді як 0 == xможе бути більш загальним (і дорогим) порівняння числових значень.
Все-таки я не хотів би працювати на начальника, який думає в цих умовах ...
Безумовно, різниці в швидкості виконання. Стан необхідно оцінювати в обох випадках однаково.
Я думаю, що найкраща відповідь - "на якій мові цей приклад"?
Питання не вказувало мову, і вона позначена як "C" та "C ++". Точна відповідь потребує додаткової інформації.
Це запитання щодо програмування, але це може бути корисним у недоброзичливому підрозділі "давайте опитуваному достатньо мотузки, щоб або повісити себе, або побудувати гойдалку на дереві". Проблема таких питань полягає в тому, що вони, як правило, записуються і передаються від інтерв'юера до інтерв'юера, поки не потраплять до людей, які насправді не розуміють цього з усіх кутів.
Побудуйте дві прості програми, використовуючи запропоновані способи.
Зберіть коди. Подивіться на збори, і ви можете судити, але я сумніваюся, що є різниця!
Інтерв'ю стає нижчим, ніж будь-коли.
Так само, як і в сторону (я фактично думаю, що будь-який гідний компілятор зробить це питання спірним, оскільки він оптимізує його), використовуючи 0 == прапор над прапором == 0, перешкоджає помилковому друку, де ви забудете один із знаків = (тобто якщо випадково введете flag = 0 він буде компілюватися, але 0 = прапор не буде), що, на мою думку, є помилкою, яку всі зробили в той чи інший момент ...