if (flag == 0) 또는 if (0 == flag) 중 어느 것이 더 빨리 실행됩니까?


111

인터뷰 질문 : 한 빨리 실행됩니다 if (flag==0)또는 if (0==flag)? 왜?


330
가장 어리석은 인터뷰 질문에 지명되었습니다. 그리고 치열한 경쟁이 있습니다.
Konrad Rudolph 2011 년

119
당신 :이 둘의 차이가 귀찮을만한 가치가있는 상황을 말하십시오. 면담 자 : 좋아요, 당신은 고용되었습니다.
Chris Lutz 2011 년

37
둘 사이의 유일한 차이점은 이후의 규칙에서는 if(flag = 0)약간의 가독성을 제공하는 대가로 버그에 대해 보험을들 수 있다는 것입니다.
Amarghosh 2011 년

22
@Amarghosh : 코드를 읽기 어렵고 직관적이지 않게 만드는 대가로. 컴파일러 경고, win-win에서 전자를 사용하십시오.
GManNickG 2011 년

129
한 컴파일러 작가가 인터뷰에서 이것을 얻었습니다. 그는 응답 속삭였다 "사람은 할 수있는 당신이 빨리되고 싶어?".

답변:


236

나는 아직 정답을 보지 못했습니다 (그리고 이미 일부가 있습니다) 경고 : Nawaz는 사용자 정의 트랩을 지적했습니다 . 그리고 "가장 어리석은 질문"에 대해 서둘러 찬성 투표를 한 것을 후회합니다. 많은 사람들이 제대로 이해하지 못한 것 같고 컴파일러 최적화에 대한 좋은 토론의 여지를 제공합니다. :)

정답은:

flag유형 은 무엇입니까 ?

경우 여기서 flag실제로 사용자 정의 형식이다. 그런 다음 어떤 과부하 operator==가 선택 되었는지에 따라 다릅니다 . 물론 그것들이 대칭 적이 지 않다는 것은 어리석은 것처럼 보일 수 있지만, 그것은 확실히 허용되며, 이미 다른 학대를 보았습니다.

flag가 내장 된 경우 둘 다 동일한 속도를 가져야합니다.

에 대한 Wikipedia 기사 에서 x86나는 진술 에 대한 Jxx지침을 if기대할 것 JNZ입니다.

최적화가 꺼져 있어도 컴파일러가 그러한 명백한 최적화를 놓치는 것은 의심 스럽습니다. 이것은 Peephole Optimization 이 설계된 유형입니다 .

편집 : 다시 시작되었으므로 어셈블리를 추가해 보겠습니다 (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을 읽는 방법을 모르더라도 자명하다고 생각합니다.


4
@Matthieu : 당신이 말한 내가 아직 정답을 보지 못했다 ..하지만 내가 올바른지, 내가 생각 : P
나와 즈

7
좋은! 당신의 대답은 "가장 어리석은 질문"이 "가장 속임수 / 중요 함"으로 바뀝니다. "후보를 위해 구멍을 파고 그가 그것에 빠지는 지 보자 ...":) 나는 우리 모두가 자동으로 그것이 flag정수 또는 부울이어야 한다고 가정한다고 생각한다 . OTOH,라는 변수를 갖는 flag사용자 정의 유형은, 이럴 자체에 매우 잘못된 것입니다
davka

@Nawaz : 답변의 마지막 단락을 건너 뛰었을 수 있습니다. p
Matthieu M.

1
@Nawaz : 저는 정말 경주하지 않습니다. 저는 보통 질문에 대한 답변을받은 후 오랫동안 질문을 읽고 사람들은 가장 먼저 가장 많이 찬성 된 답변 만 읽는 경향이 있습니다. :)하지만 실제로는 컴파일러 최적화에 대한 내용을 읽고 있는데 이것은 사소한 최적화의 전형적인 경우이므로 실제로 귀찮은 독자들에게 지적 할 것이라고 생각했습니다. 실제로 너무 많은 찬성표를 얻었습니다. :) / 어쨌든 내가 편집 한 내 대답은 내 문을 수정 : 지금은 내 대부분의 그것이 내가 가장 노력을하는 사람이 확실히 비록 대답을 선정이다
매튜 M.

2
@mr_eclair : 기본 제공 유형은 (이름에서 알 수 있듯이) 언어에 기본 제공되는 유형입니다. 즉, 단일 #include지시어 없이도 사용할 수 있습니다 . 단순화하기 위해, 보통 금액 int, char, bool등이있다. 다른 모든 유형이 그들을 선언 유저의 결과이기 때문에 그들이 존재 즉, 사용자 정의로 말한다 : typedef, enum, struct, class. 예를 들어, std::string사용자가 정의한 것입니다. 확실히 직접 정의하지는 않았지만 :)
Matthieu M.

56

GCC 4.1.2를 사용하는 amd64에 대한 동일한 코드 :

        .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

18
컴파일러 최적화가 동일하다는 것을 증명하기 위해 추가 마일을 가면 +1.
k rey

56

버전에는 차이가 없습니다.

typeof 플래그가 사용자 정의 유형이 아니라 일부 내장 유형 이라고 가정하고 있습니다. Enum은 예외입니다! . enum을 내장 된 것처럼 취급 할 수 있습니다. 사실, 그것의 값은 내장형 중 하나입니다!

사용자 정의 유형 (제외 enum) 인 경우 대답은 전적으로 연산자를 오버로드 한 방법에 따라 달라집니다 ==. ==각 버전에 대해 하나씩 두 개의 함수를 정의 하여 오버로드 해야합니다!



15
현대 컴파일러가 이러한 명백한 최적화를 놓친다면 매우 놀랄 것입니다.
Pedro d' Aquino 2011 년

3
내 지식에! 비트 연산이 아닙니다
Xavier Combelle 2011 년

8
@Nawaz : 반대표를 던지지는 않았지만 귀하의 대답은 사실적으로 잘못되었으며 여전히 많은 찬성표를 얻은 것은 끔찍합니다. 기록을 위해 정수를 0과 비교하는 것은 단일 어셈블리 명령어 이며 완전히 부정과 동등합니다. 사실, 컴파일러가 약간 어리 석다면 부정보다 빠를 수도 있습니다 .
Konrad Rudolph 2011 년

6
@Nawaz : 그것이 더 빠를 수 있고, 의지하거나, 일반적으로 할 것이라고 말하는 것은 여전히 ​​잘못입니다. 차이가 있으면 부정 1이 실제로 "부정 피연산자, 결과가 0이 아닌지 확인"이라는 두 가지 연산으로 변환되기 때문에 "0과 비교"버전이 더 빠릅니다. 물론 실제로 컴파일러는이를 최적화하여 일반 "0과 비교"버전과 동일한 코드를 생성하지만 최적화는 부정 버전에 적용되어이를 따라 잡기 위해 적용됩니다. 콘라드가 옳다.
jalf

27

전혀 차이가 없습니다.

하지만 다음과 같이 할당 / 비교 오타 제거를 참조하여 인터뷰 질문에 답할 때 점수를 얻을 수 있습니다.

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


@Matthieu 허. "적절한"브레이싱 스타일을 설명하는 메타에 대한 게시물을 놓친 것 같습니다 .
Linus Kleen 2011 년

7
나는 전혀 투표하지 않았지만 그 가치에 대해 투표했습니다. 사람들이 투표 할 때마다 자신을 설명하는 것이 왜 그렇게 중요한가요? 투표는 의도적으로 익명으로 처리됩니다. 저는 개인적으로 문제를 지적하는 코멘트를 남겼다고해서 다운 투표자로 간주되는 것을 결코 원하지 않기 때문에 비추천자가 항상 언급해야한다는 생각에 전적으로 반대합니다. 아마도 반대 투표자는 대답의 대부분이 속도 질문과 관련이 없다고 생각했을까요? 그가 승인하지 않은 코딩 스타일을 장려한다고 생각했을까요? 아마도 그는 성기 였고 자신의 답변이 최고 등급을 받기를 원했을까요?
David Hedlund 2011 년

3
사람들은 이유에 관계없이 자유롭게 투표 할 수 있어야합니다. 평판 측면에서, 이것은 종종 다른 사람들에게 업 보트를 유발하고 과분한 다운 보트에 대응하도록 유도하기 때문에 거의 항상 좋은 것입니다.
David Hedlund 2011 년

26
@David :이 사이트는 비밀 인기 투표 용지, 익명 투표 등에 관한 것이 아니기 때문에 반대 투표자는 스스로 설명해야합니다. 이 사이트는 학습에 관한 것입니다. 누군가가 반대 투표로 응답이 틀렸다고 말하는 경우, 반대 투표자는 이유를 설명하지 않으면 자신의 지식으로 이기적인 것입니다. 그들은 자신이 옳을 때 모든 공로를 인정하지만 다른 사람이 틀렸을 때 지식을 공유하지 않습니다.
John

1
브레이싱 스타일 문제를 없애기 위해 Matthieu가 그것을 농담으로 의도했다고 생각합니다. 누구든지 그런 문제에 따라 투표를하는 것을 보면 놀랄 것입니다. 그렇긴하지만 모든 사람이 똑같은 방식으로 투표를 사용하는 것은 아닙니다. 포스트는 유권자의 승인 할 수있는 코딩 스타일을 옹호하는 것 때문에 내가 downvoting에 대한 이론적 근거를 볼 수 있었다 (사이의 차이에 유의 옹호 코딩 스타일을 - "이 같은 코드를 작성하는 경우, 당신은 할 때 컴파일러 오류가 발생합니다 단순히 -이 오타 " 를 사용 한다는 점에서 같은 중괄호와 같은 코딩 스타일을) ...
데이비드 Hedlund는

16

속도면에서 전혀 차이가 없습니다. 왜 있어야합니까?


7
컴파일러가 완전히 지연된 경우. 그게 유일한 이유입니다.
JeremyP 2011 년

@JeremyP : 컴파일러가 지연된 경우에도 차이를 상상할 수 없습니다. 컴파일러 작성자는 내가 말할 수있는 한 고의로 해야합니다 .

2
프로세서에 "test if 0"명령이 있다고 가정하면 x == 0이를 사용할 수 있지만 0 == x일반 비교를 사용할 수 있습니다. 나는 그것이 지연되어야한다고 말했었다.
JeremyP 2011 년

8
플래그 () == 연산자 비대칭 과부하 사용자 정의 형식 인 경우
OrangeDog

때문에 우리는 할 수 있는 virtual operator==(int)사용자 정의 유형에?
lorro

12

플래그가 사용자 정의 유형일 때 차이가 있습니다.

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과 비교됩니다. 두 번째 경우에는 == 연산자가 호출됩니다.


3
+1은 전환 연산자가 operator ==만큼 관련 될 수 있음을 나타냅니다.
Tony Delroy 2011

11

의심 스러울 때 그것을 벤치마킹하고 진실을 배우십시오.


2
벤치마킹에 어떤 문제가 있습니까? 때로는 연습은 이론보다 더 당신을 말하고있다
Elzo Valugi

1
이것이 제가이 글을 읽기 시작했을 때 찾던 답입니다. 이 이론은 더 답변 upvotes : 연습보다 매력적 찾고있는 것 같다
사무엘 리 바스를

인터뷰에서 어떻게 벤치마킹 할 수 있습니까? 게다가 면접관은 벤치마킹이 무엇을 의미하는지조차 모른다고 생각합니다. 그래서 그는 기분이 상했을 수도 있습니다.
IAdapter 2011 년

질문 (IMO)에 대한 정답은 "컴파일러와 나머지 프로그램에 따라 다릅니다. 벤치 마크를 작성하고 5 분 안에 테스트하겠습니다."
Samuel Rivas

7

속도면에서 정확히 동일해야합니다.

그러나 어떤 사람들은 (등등 비교 =연산자) 대신 (할당 연산자) 를 쓰면 발생할 수있는 모든 오류를 피하기 위해 등식 비교 (소위 "Yoda conditionals")에서 상수를 왼쪽에 두는 데 사용합니다 ==. 리터럴에 할당하면 컴파일 오류가 발생하므로 이러한 종류의 실수를 방지 할 수 있습니다.

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
{

}

반면에, 대부분의 사람들은 "Yoda conditional"이 이상하고 성가 시다고 생각합니다. 특히 적절한 컴파일러 경고를 사용하여 예방하는 오류 클래스를 발견 할 수 있기 때문입니다.

if(flag=0) // <--- warning: assignment in conditional expression
{

}

반향 주셔서 감사합니다. 그러나 예를 들어 PHP는 조건부 할당의 경우 경고하지 않습니다.
Linus Kleen 2011 년

5

다른 사람들이 말했듯이 차이가 없습니다.

0평가해야합니다. flag평가해야합니다. 이 프로세스는 어느쪽에 배치 되든 동일한 시간이 걸립니다.

정답은 둘 다 같은 속도입니다.

심지어 표현 if(flag==0)if(0==flag)문자 같은 양의있다! 그들 중 하나가로 작성 되었다면 if(flag== 0)컴파일러는 파싱 할 추가 공간을 하나 갖게되므로 컴파일 시간을 지적 할 합법적 인 이유가있을 것입니다.

그러나 그런 것이 없기 때문에 어떤 사람이 다른 사람보다 더 빨라야 할 이유가 전혀 없습니다. 이유가 있다면 컴파일러는 생성 된 코드에 매우 이상한 일을하고 있습니다.


5

어느 것이 빠른지 사용하는 == 버전에 따라 다릅니다. 다음은 ==의 두 가지 가능한 구현을 사용하는 스 니펫이며 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);
}

5

글쎄, 나는 운동을 위해 OP에 대한 의견에서 말한 모든 것에 완전히 동의합니다.

컴파일러가 충분히 영리하지 않거나 (실제로 사용해서는 안 됨) 최적화가 비활성화 된 x == 0경우 네이티브 어셈블리 jump if zero명령어로 컴파일 0 == x할 수있는 반면 숫자 값을보다 일반적 (비용이 많이 드는) 비교가 될 수 있습니다.

그래도 이런 식으로 생각하는 상사를 위해 일하고 싶지 않습니다 ...


4

실행 속도면에서 분명히 차이가 없습니다. 두 경우 모두 동일한 방식으로 조건을 평가해야합니다.


3

가장 좋은 대답은 "이 예제는 어떤 언어로되어 있습니까?"라고 생각합니다.

질문은 언어를 지정하지 않았으며 'C'와 'C ++'태그가 모두 붙어 있습니다. 정확한 답변에는 더 많은 정보가 필요합니다.

형편없는 프로그래밍 질문이지만, "인터뷰 대상에게 목을 매달거나 나무 그네를 만들 수있는 충분한 밧줄을 줍시다"부서에서는 좋은 질문이 될 수 있습니다. 이런 종류의 질문의 문제는 일반적으로 모든 각도에서 그것을 이해하지 못하는 사람들에게 도달 할 때까지 면접관에서 면접관에게 기록되고 전달된다는 것입니다.


3

제안 된 방법을 사용하여 두 개의 간단한 프로그램을 빌드하십시오.

코드를 조립하십시오. 어셈블리를보고 판단 할 수 있지만 차이가있는 것 같지 않습니다!

인터뷰는 그 어느 때보 다 낮아지고 있습니다.


2

제쳐두고 (실제로 괜찮은 컴파일러 가이 질문을 할 것이라고 생각합니다. 최적화 할 것이기 때문에) 0 == flag over flag == 0을 사용하면 = 중 하나를 잊어 버리는 오타를 방지합니다. flag = 0 컴파일되지만 0 = flag는 그렇지 않습니다), 나는 모든 사람들이 한 지점에서 또는 다른 지점에서 실수를 저지른 것이라고 생각합니다.


0

차이가 있다면 컴파일러가 더 빠른 것을 선택하는 것을 막는 것은 무엇입니까? 따라서 논리적으로 차이가있을 수 없습니다. 아마도 이것이 면접관이 기대하는 것입니다. 사실 그것은 훌륭한 질문입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.