両方のループは無限ですが、反復ごとにどちらがより多くの命令/リソースを必要とするかを確認できます。
gccを使用して、次の2つのプログラムをコンパイルして、さまざまなレベルの最適化でアセンブリしました。
int main(void) {
    while(1) {}
    return 0;
}
int main(void) {
    while(2) {}
    return 0;
}
最適化を行わなくても(-O0)、生成されたアセンブリは両方のプログラムで同一でした。したがって、2つのループ間に速度の違いはありません。
参考までに、生成されたアセンブリを以下に示します(gcc main.c -S -masm=intel最適化フラグを使用)。
と-O0:
    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    push    rbp
    .seh_pushreg    rbp
    mov rbp, rsp
    .seh_setframe   rbp, 0
    sub rsp, 32
    .seh_stackalloc 32
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"
と-O1:
    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    sub rsp, 40
    .seh_stackalloc 40
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"
-O2し、-O3(同じ出力):
    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .section    .text.startup,"x"
    .p2align 4,,15
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    sub rsp, 40
    .seh_stackalloc 40
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"
実際、ループ用に生成されたアセンブリは、最適化のすべてのレベルで同じです。
 .L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"
重要なビットは:
.L2:
    jmp .L2
アセンブリをうまく読み取ることができませんが、これは明らかに無条件ループです。このjmp命令は.L2、値をtrueと比較することさえせずに、無条件にプログラムをラベルにリセットします。もちろん、プログラムが何らかの形で終了するまで、すぐに再びリセットします。これはC / C ++コードに直接対応します。
L2:
    goto L2;
編集:
興味深いことに、最適化を行わなくても、次のループはすべてjmpアセンブリでまったく同じ出力(無条件)を生成しました。
while(42) {}
while(1==1) {}
while(2==2) {}
while(4<7) {}
while(3==3 && 4==4) {}
while(8-9 < 0) {}
while(4.3 * 3e4 >= 2 << 6) {}
while(-0.1 + 02) {}
そして私の驚きにも:
#include<math.h>
while(sqrt(7)) {}
while(hypot(3,4)) {}
ユーザー定義関数を使用すると、少し面白くなります。
int x(void) {
    return 1;
}
while(x()) {}
#include<math.h>
double x(void) {
    return sqrt(7);
}
while(x()) {}
に -O0、これらの2つの例が実際に呼び出さxれ、各反復の比較が実行されます。
最初の例(1を返す):
.L4:
    call    x
    testl   %eax, %eax
    jne .L4
    movl    $0, %eax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"
2番目の例(を返すsqrt(7)):
.L4:
    call    x
    xorpd   %xmm1, %xmm1
    ucomisd %xmm1, %xmm0
    jp  .L4
    xorpd   %xmm1, %xmm1
    ucomisd %xmm1, %xmm0
    jne .L4
    movl    $0, %eax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"
ただし、 -O1それ以降は、どちらも前の例と同じアセンブリを生成します(jmp前のラベルに無条件に戻る)。
TL; DR
GCCでは、さまざまなループが同じアセンブリにコンパイルされます。コンパイラーは定数値を評価し、実際の比較を実行する必要はありません。
物語の教訓は:
- C ++ソースコードとCPU命令の間には変換の層があり、この層はパフォーマンスに重要な影響を与えます。
 
- したがって、ソースコードだけを見てパフォーマンスを評価することはできません。
 
- コンパイラーは、そのような些細なケースを最適化するのに十分スマートでなければなりません。プログラマーは、大多数のケースでそれらについて考えることに時間を無駄にすべきではありません。