またベンチマーク
ベンチマーク厨とでも呼んで下さい。
参照:http://proglang-0.ten.thebbs.jp/1079174593/
このスレッドでちょっと興味を持ったので、char配列の初期化について調べてみた。このスレッドに書いたこととも重複するけど、まとめの意味です。Cで文字列を初期化(空文字列)にするときは以下のような方法が考えられます。
(1) char str[1024] = {0}; (2) char str[1024] = ""; (3) char str[1024]; str[0] = '\0';
はじめに言っておきますが、ダントツで(3)が最速です。というか、そもそも意味が違います。(1),(2)はそれぞれstr配列の領域すべてを0で初期化しますが、(3)は最初の要素のみ初期化します(文字列的にはこれでOK)。
1,000,000回上記3通りの初期化をループしたところ結果は
(1) 1.14 sec (2) 0.43 sec (3) 0.01 sec コンパイルは[gcc -O2 benchmark.c]としました。
となりました。もはや結果はどうでもよいです。文字列の初期化ってあんまり使わないし(大抵は明示的にstrncpyやsnprintfなどで具体的な文字を代入してしまうので、初期化は必要無い)、必要があるなら(3)でOKでしょう。見た目がうざったくに見えるなら
#define initstr(s) s[0] = '\0' char str[1024]; initstr(str);
とすれば良いでしょう。むしろ気になったのはなんで(1)があんなに遅いのかってこと。アセンブラに落してみたらこうなりました(一部抜粋)
subl $1036, %esp pushl $1023 movb .LC0, %al movb %al, -1032(%ebp) pushl $0 leal -1031(%ebp), %eax pushl %eax call memset
おぉい、なんでmemset呼んでるんだい? アセンブリ言語ってあんまり流暢じゃないんだけど、もっと上手いやり方ありそうだけどなぁ。ちなみに(2)はこうなる。
cld pushl %edi movl $256, %ecx leal -1032(%ebp), %edi xorl %eax, %eax subl $1028, %esp rep stosl movl -4(%ebp), %edi
やっぱ、奇麗だね。(1)の方をrep stoslで置き換えてみたけど、あんまり速くならなかった。もしかして、memsetが問題なんじゃなくて、movb .LC0, %alのほうが問題。ともかく餅は餅屋で、配列の初期化は配列の初期化用の構文使うのが良い、と。