C言語のwhileとdo-whileに速度の違いはあるのか。

友人に whileとdo-whileに速度の違いはあるのか? というような質問をされました。 考えたこともなかったので、ちょっと色々やってみました。

とりあえず書いてみたコードがこれ。

#include <stdio.h>

int main(){
    int i=0;

    while(i<1000000000){
        i++;
    }

    return 0;
}

これがwhile版。

#include <stdio.h>

int main(){
    int i=0;

    do{
        i++;
    }while(i<1000000000);

    return 0;
}

こっちがdo-while版。 どちらもほぼ同じで、10億回ループするだけのコードです。

で、GCCでアセンブリにしてみる。

$ gcc -O0 -S while.c

コマンドはこんな感じ。

まずはwhile版。

    .file	"while.c"
    .text
    .globl	main
    .type	main, @function
main:
.LFB0:
    .cfi_startproc
    pushq	%rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq	%rsp, %rbp
    .cfi_def_cfa_register 6
    movl	$0, -4(%rbp)
    jmp	.L2
.L3:
    addl	$1, -4(%rbp)
.L2:
    cmpl	$999999999, -4(%rbp)
    jle	.L3
    movl	$0, %eax
    popq	%rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size	main, .-main
    .ident	"GCC: (Gentoo 4.8.4 p1.5, pie-0.6.1) 4.8.4"
    .section	.note.GNU-stack,"",@progbits

ラベル2つも使うんですね。おもしろい。

で、do-while版がこちら。

    .file	"do-while.c"
    .text
    .globl	main
    .type	main, @function
main:
.LFB0:
    .cfi_startproc
    pushq	%rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq	%rsp, %rbp
    .cfi_def_cfa_register 6
    movl	$0, -4(%rbp)
.L2:
    addl	$1, -4(%rbp)
    cmpl	$999999999, -4(%rbp)
    jle	.L2
    movl	$0, %eax
    popq	%rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size	main, .-main
    .ident	"GCC: (Gentoo 4.8.4 p1.5, pie-0.6.1) 4.8.4"
    .section	.note.GNU-stack,"",@progbits

お、ラベルが少ない。 ぱっと見こちらの方がシンプルな仕上がりになっています。行数も少ないし。

なるほど、do-whileの方が速いんだね。・・・とは言い難いので、実測値。 timeコマンドのuserの値を5つ。

while [秒]do-while [秒]
1回目1.6031.601
2回目1.5971.609
3回目1.6111.597
4回目1.6081.597
5回目1.6061.604
平均1.6151.602

・・・うーん。

結論: whileとかdo-whileとかどっちでもいいから、効率的なアルゴリズムを考えなさい。