Duffという人が考えた Duff's deviceという、有名なC言語のトリッキーコードがあります^^;)
それがこちらのコード↓↓
/* countは 「 必ずcount > 0 である」という前提 */
switch (count % 8)
{
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while ((count -= 8) > 0);
}
do {} whileの中にcase文が入っていて、見るからに怪しさ満点のコードなのですが、
なんとビックリ、このコードはC言語の正当なコーディング手法なんだそうです! ( ゚Д゚)・・・ポカーン
※ 補足しておくと、case文とはただのラベルに過ぎず、ブロック中にあっても有効
(これをcaseラベルのfall-through特性というらしい)との事。
そして、上記コードは、以下のコードを最適化したものです。
do {
*to = *from++;
} while (--count > 0);
連続コピーを行うコードなのですが、
メモリマップされたデバイスの出力レジスタへのコピーの為、*toにインクリメントがつきません。
ループ展開することによって、処理を高速化しています。
・・・ということで、早速テスト開始~♪
#include <stdio.h>
#include <string.h>
#include <malloc.h>
int main(void)
{
char * psz1 = calloc(100, sizeof(char));
char * psz2 = "abcdefghijklmnopqrstuvwxyz";
char * to = psz1;
char * from = psz2;
int count = (int)strlen(from);
do {
*to++ = *from++;
} while (--count > 0);
// *to = NULL;
puts(psz1);
puts(psz2);
}
文字列をコピーするテストコードです^^;)
PCでテストする際は、*toにインクリメントをつけます。
また、callocではなくmallocでメモリ領域を割当てた場合は、最後に *to = NULLをするのを忘れないようにします。
実行結果は以下の通り
そして、Duff's device風にコードを書き換えて実行してみます。
#include <stdio.h>
#include <string.h>
#include <malloc.h>
int main(void)
{
char * psz1 = calloc(100, sizeof(char));
char * psz2 = "abcdefghijklmnopqrstuvwxyz";
char * to = psz1;
char * from = psz2;
int count = (int)strlen(from);
switch (count % 8) {
case 0: do { *to++ = *from++;
case 7: *to++ = *from++;
case 6: *to++ = *from++;
case 5: *to++ = *from++;
case 4: *to++ = *from++;
case 3: *to++ = *from++;
case 2: *to++ = *from++;
case 1: *to++ = *from++;
} while ((count -= 8) > 0);
}
puts(psz1);
puts(psz2);
}
実行結果は以下の通り
最適化前のコードと同じ動作をしていることが、無事に確認できました~^^;)
ちなみに、最適化前コードの以下の部分は、
int count = (int)strlen(from);
do {
*to++ = *from++;
} while (--count > 0);
以下の様に書き直すことができます。
while (*to++ = *from++);
K&Rで推奨されている、strcpyのやり方です。
ひょっとしたら参考になるかもしれないページ : switchステートメント