2007年 05月 02日
共用体+ビットシフト演算子 |
今日、初めて「プログラミングって面白い!」と思った。
興味がないっていう人は、途中流し見で結構です。
「ローテートを行う関数を作りなさい」という問題。
ローテート(10010010→00100101、みたいなのね)を行う演算子が
Cにはないので、ビットシフト演算子をどうにか駆使して関数を作れ、と。
解答例はこんな感じ。
#include <stdio.h>
void rotate(unsigned char *c);
int main(void)
{
unsigned char;
int i;
ch = 1; /* わかりやすく1から始めてみよう */
for(i=0; i<16; i++)
{
rotate(&ch);
printf("%u \n", ch);
}
return 0;
}
void rotate(unsigned char *c)
{
union
{
unsigned char ch[2];
unsigned u;
} uni;
uni.u = 0; /* ここで16ビットをクリア */
uni.ch[0] = *c;
uni.u = (uni.u << 1); /* 整数を左に1シフト */
if(uni.ch[1]) /* ビットがch[1]にシフトしてたら真 */
{
uni.ch[0] = uni.ch[0] | 1; /* OR演算でch[0]の端へ */
}
*c = uni.ch[0];
}
このプログラムを実行すると
2
4
8
16
32
64
128
1
2
4
:
:
ってなるんですが(ch = 1のときね)、つまりは
00000010
00000100
00001000
00010000
00100000
01000000
10000000
00000001
00000010
00000100
:
:
ってこと。(字下げが面倒だ…)
となると、メモリやCPUの動きについてもすごく気になり始める。
4ビットのデータを確保してるメモリから1つ左にビットシフトしたら、
一つ下のメモリアドレスに入ってるデータの尻に
はみ出した1ビットのデータを引っ付けるって、どうやって処理するのか?
CPUは0と1の組み合わせ、
正確に言えば、電流のON/OFFで演算をしてるらしいけど、
じゃシフト演算ではみ出した部分はどこへ行くのか?
どうやって「このビットは消してもいいや」って判断するのか?
単純に0/1だけで動いてるとは思えないほど複雑。
もしかしたら何年もCをやってる人にはすごく簡単な問題かもしれないし、
研修担当の上司が「どうかなー、この問題」って言ってたので、
実際使うことはほとんどないテクニックなんでしょう。
でも、このプログラムを見て僕は感動したわけです。
共用体自体、業務ではあんまり使う機会がないそうなんですが、
僕にはすごく気になる存在なのです。日陰に咲く花のように。
それが、こんなとこで役に立つなんて(役に立ってないんだが)。
僕にプログラムとコンピュータの奥深さを思い知らせてくれるなんて。
うーむ、まだまだ未熟で上手く説明できんな。
この感動が伝わったでしょうか?C経験者の皆様。
興味がないっていう人は、途中流し見で結構です。
「ローテートを行う関数を作りなさい」という問題。
ローテート(10010010→00100101、みたいなのね)を行う演算子が
Cにはないので、ビットシフト演算子をどうにか駆使して関数を作れ、と。
解答例はこんな感じ。
#include <stdio.h>
void rotate(unsigned char *c);
int main(void)
{
unsigned char;
int i;
ch = 1; /* わかりやすく1から始めてみよう */
for(i=0; i<16; i++)
{
rotate(&ch);
printf("%u \n", ch);
}
return 0;
}
void rotate(unsigned char *c)
{
union
{
unsigned char ch[2];
unsigned u;
} uni;
uni.u = 0; /* ここで16ビットをクリア */
uni.ch[0] = *c;
uni.u = (uni.u << 1); /* 整数を左に1シフト */
if(uni.ch[1]) /* ビットがch[1]にシフトしてたら真 */
{
uni.ch[0] = uni.ch[0] | 1; /* OR演算でch[0]の端へ */
}
*c = uni.ch[0];
}
このプログラムを実行すると
2
4
8
16
32
64
128
1
2
4
:
:
ってなるんですが(ch = 1のときね)、つまりは
00000010
00000100
00001000
00010000
00100000
01000000
10000000
00000001
00000010
00000100
:
:
ってこと。(字下げが面倒だ…)
となると、メモリやCPUの動きについてもすごく気になり始める。
4ビットのデータを確保してるメモリから1つ左にビットシフトしたら、
一つ下のメモリアドレスに入ってるデータの尻に
はみ出した1ビットのデータを引っ付けるって、どうやって処理するのか?
CPUは0と1の組み合わせ、
正確に言えば、電流のON/OFFで演算をしてるらしいけど、
じゃシフト演算ではみ出した部分はどこへ行くのか?
どうやって「このビットは消してもいいや」って判断するのか?
単純に0/1だけで動いてるとは思えないほど複雑。
もしかしたら何年もCをやってる人にはすごく簡単な問題かもしれないし、
研修担当の上司が「どうかなー、この問題」って言ってたので、
実際使うことはほとんどないテクニックなんでしょう。
でも、このプログラムを見て僕は感動したわけです。
共用体自体、業務ではあんまり使う機会がないそうなんですが、
僕にはすごく気になる存在なのです。日陰に咲く花のように。
それが、こんなとこで役に立つなんて(役に立ってないんだが)。
僕にプログラムとコンピュータの奥深さを思い知らせてくれるなんて。
うーむ、まだまだ未熟で上手く説明できんな。
この感動が伝わったでしょうか?C経験者の皆様。
by novaexp
| 2007-05-02 21:02