what you see is what you get

名前だけでも覚えて帰ってください

僕なりにポインタの説明を考えてみた。

現在研修で新入社員にC言語を教えてるのですが、やっぱポインタは鬼門。
分かってしまえばどーってことないのだけど、あの特殊な文法は迷わせるよね。

特にポインタ変数を宣言するときは

int *a;

って宣言して
で、「ポインタはアドレスだよ」と習うので、
aのアドレスを表示させようとして

printf("%p", *a);    // ERROR

と書いてコンパイラに怒られてしまってどうしようもなくなってしまったり。

ただ文法もそうなのだけど、それ以上に概念がつかめない人が多いこともわかった。
特に今は大学で「プログラムやってました!」って人も
MATLABでシミュレーションだったりWeb系の言語だったりで
メモリを叩いたりする経験がないことが多いので
いきなり「これがメモリの中身で、そのなかにアドレスが振られててさー」と言っても
イメージすることが難しいみたい。

で、どう説明するものかお風呂の中でボーッと考えてたら
なんかイメージが浮かんだので書いてみる。
古参の方から見ればゆとりに感じてしまうかもしれない例えかもしれませんが。

もし間違いをしていましたらお手数ですがご指摘いただけると助かります。
解説文なので間違いがあったら多くの人に迷惑をかけるので
致命的な間違いがあれば引っ込めます。

変数の型はファイル形式だ

intとかcharとかfloatとかstructとか配列とかいろいろあるけど
ここでは「ファイルの形式だ」とイメージしよう。
パソコンの中ではtxtとかdocとかmp3とか
いろいろ収納しているデータによってファイルの形式が違うよね。

ポインタ型は「エイリアス」「ショートカット」だ

じゃあここでポインタ型にあてはまるるものはなにかというと
Macだったら「エイリアス」、Windowsだったら「ショートカット」
をイメージしてほしい。

以下Windowsユーザは「エイリアス」を「ショートカット」に読み替えること。

Macで適当なファイルのエイリアスをつくって
そのエイリアスのファイルの情報を見てみよう。
僕はiTunesにいれているPerfumeのmp3ファイルでエイリアスを作ってみた。

まず注目して欲しいのは「オリジナル」のところ。
このPerfumeポリリズムのmp3のファイルの本体は

/Users/kskktk/Music/iTunes/iTunes Media/Music/Perfume/Polyrhythm/Perfume - Polyrhythm.mp3

って場所にあることが分かる。
またあとで説明に使うから「場所」のところも確認しておいてほしい。
このポリリズムエイリアスファイルはデスクトップにおいてるってことが分かる。
エイリアスファイルもファイルだから
そいつ自身にもありかがあるのは当たり前っちゃー当たり前。

エイリアスファイルはファイルそのものではない

ここで気をつけるべきことは
エイリアスファイルはそのファイルそのものではないということ。
このエイリアスファイルをクリックしたらポリリズムが流れるだろうけど
それはエイリアスファイルが「オリジナル」で指し示しているファイルを選択して
その先に格納されているmp3データを再生してくれてるのだった。

エイリアスファイルをデスクトップに作成しても
そのオリジナルのファイルがコピーされてくるわけではない。
エイリアスファイルを作成するってことは
オリジナルファイルがどこにあるかを覚えているファイルを作っただけ

エイリアスファイル自体にはテキストも音楽も画像も保存できない。
あくまで保存できるのはそのファイルがどこにあるかだ。

ポインタ型変数の宣言

さて今まで上で説明したイメージでCのポインタの文法を考えてみよう。

ポインタ型の宣言を考えてみよう。さっきも書いたこれ。

int *a;

これは「int型を指すポインタ変数a」を宣言したんだった。

ここで注意すべき、初心者が間違える落とし穴がここにあって
上の宣言で作った変数はあくまでも"a"って変数で
決して"*a"って変数を作ったのではないということ。
「aの中にアドレスを入れますよ」という意味で*を付けただけ。
型宣言だと思えばいい。
これがCの文法の分かりにくいところだよね。
「え?サンプルプログラムの中では*aって変数出てきたよ?」って思った人も
それはあとで説明するからそのまま読み進めてほしい。

さてこれを先ほどのイメージで読み替えると
mp3ファイルのありかを保存できるエイリアスaを宣言した
みたいなイメージだ。

aはあくまでもエイリアスだからファイルのありかしか保存できない。
つまりポインタ変数aはアドレスしか保存できないってことと同じ。
具体的な値を代入したり、その値そのものを見たりすることはできないんだった。

ただエイリアスファイルは
mp3ファイルだろうがdocファイルだろうがなんでも一つで扱えたけど
Cでポインタ変数を定義するときは
そいつがなんのアドレスを保存できるかってのを
明示的に知らせてあげないといけないってルールがある。

int *a;

と宣言したときは、aが保存できるのはint型のデータが格納されているアドレスだけ。
float型のデータが格納されたアドレスを保存したいときは

float *b;

って宣言しないといけない。

上のイメージを擬似的にコードにしてみると
mp3が保存されているファイルのありかを保存するエイリアスaを宣言するときは

mp3 *a;

docファイルが保存されているファイルのありかを保存するエイリアスbを宣言するときは

doc *b;

と書くようなイメージかな。

*演算子と&演算子

さてここまでの説明を踏まえて
みんなを悩ませる*演算子と&演算子を上のイメージで解説する。

まずは文法的な定義を復習しよう。

これをさっきのエイリアスのイメージで書くと

  • *aと書くとファイルのありかにあるデータそのものにアクセスできる
  • &aと書くとファイルのありかを教えてくれる

といった感じのイメージだと思えばわかりやすいかな。

以下のCの(わざとらしい)ソースコードで動きを考えてみよう。

#include<stdio.h> 

int main() 
{
    int *a;
    int b;
    
    a = &b;
    *a = 5;
    
    printf("%d\n",*a);
    printf("%p\n",a);
    printf("%p\n",&a);
    
    return 0; 
}

これを説明のためにさっきのパソコンのファイルイメージを擬似言語で書き換えてみる。
(あくまでもイメージなので細かいところはツッコまない!)

main() 
{
    txt *a;
    txt b;
    
    a = &b;
    *a = "こんにちは";
    
    print(*a);
    print(a);
    print(&a);
    
    return 0; 
}

どういうプログラムなのか一行づつ逐次解説していこう。

    txt *a;

これはテキストファイルのありかを保存できるエイリアスaを作成したというイメージ。
aにはファイルのありかを保存できる。
この時点では宣言しただけなのでaはどのファイルのありかも入っていないね。

    txt b;

これはテキストファイルbを作成したというイメージ。
ここではbはテキストファイルそのものだね。
普通のコンピュータと違うのは
新しくファイル作成するときも
自分でファイルをどこに置くかを決めることは出来ずに
コンピュータが勝手に置き場所を決めちゃうってこと。

    a = &b;

さっきの定義を思い出そう。
&をつけると「ファイルのありか」を教えてくれるんだった。
つまり&bとするとテキストファイルbのありかを教えてくれる。
aはファイルのありかを保存できるんだったから
この式は
エイリアスaにテキストファイルbのありかを覚えさせろ」
ってことね。

    *a = こんにちは;

またさっきの定義を思い出そう。
*をつけると「ファイルのありかにあるデータそのものにアクセスできる」んだった。
aにはテキストファイルbのありかが保存されているんだったね。
じゃあ*をつけたらそのファイルのありかにあるデータにアクセスできるってことだね。
つまりこの式は
エイリアスaに保存されたファイルのありかにあるテキストファイルに"こんにちは"と代入しろ」
ってこととなる。

以上がイメージできればここからは簡単。

    printf(*a);

*aだからエイリアスaが保存しているファイルのありかにあるテキストファイルの内容そのものにアクセス出来るんだね。
ということは上でエイリアスaが指すテキストファイルに"こんにちは"を代入したのだから
ここでは「こんにちは」が表示されるね。

    printf(a);

*も&もついていないただのa。
エイリアスaにはファイルのありかを保存されているのだった。
エイリアスaにはテキストファイルbのありかが保存されているのだから
ここではそのまま「テキストファイルbのありか」が表示されるね。

    printf(&a);

&だから「ファイルのありか」だね。
&aってことはエイリアスaのありかをってことだから
ここでは「エイリアスaのありか」が表示される。

上のポリリズムの例で考えると

aはエイリアスが保存しているファイルのありかだから

/Users/kskktk/Music/iTunes/iTunes Media/Music/Perfume/Polyrhythm/Perfume - Polyrhythm.mp3

が表示されて

*aはエイリアスが指しているファイルそのものだから
ポリリズムが再生されて

&aはエイリアスそのもののありかだから

/Users/kskktk/Desktop

が表示されると思えばいいね。

一旦まとめ

さてここで上記の例を踏まえていったんここで要点を整理しよう。

txt *a;

と宣言したとき

  • aはtxtファイルのファイルのありかを保存できるエイリアスである。
  • &aはエイリアス自身がどこにいるかを示す。
  • *aはエイリアスが保存しているファイルのありかにあるテキストファイルの中身を示す。
txt a;

と宣言したとき

  • aはtxtデータを保存できるファイルである。
  • &aはaに格納されているファイルのありかを示す。
  • aにはファイルのありかではなくデータが入っているのだから、*aは意味が無いし使えない。

これにならって擬似言語からC言語での説明に移ると

int *a;

と宣言したとき

  • aはintを指すアドレスを格納できる変数(つまりポインタ変数)である。
  • &aはポインタ変数そのもののアドレスを示す。
  • *aは格納されたアドレスが指し示すデータそのものを示す。
int b;

と宣言したとき

  • bはint型のデータを格納できる変数である。
  • &bはbが格納されているアドレスを指す。
  • bにはアドレスではなくデータが入っているのだから、*bは意味が無いし使えない。

C言語での表現に再挑戦

以上を踏まえて再度このソースを読もう。

#include<stdio.h> 

int main(void) 
{
    int *a;
    int b;
    
    a = &b;
    *a = 5;
    
    printf("%d\n",*a);
    printf("%p\n",a);
    printf("%p\n",&a);
    
    return 0; 
}
    int *a;
    int b;

これは上で説明したから割愛する。
aはアドレスを、bは実数値を格納できるんだった。

    a = &b;

aには*も&もついていないからaにはアドレスが格納できるんだった。
bには&がついているから、&bは変数bのアドレスを示すんだね。
つまりこれは
「変数bのアドレスをポインタaに格納しろ」ってことだ。

    *a = 5;

こんどはaに*がついている。
ポインタに*がついているってことはポインタに格納されているアドレスに入ってるデータを示すんだった。
つまりこれは
「ポインタaが指すアドレスに格納されているデータに5を代入しろ」ってことか。
「ポインタaが指すアドレスに格納されているデータ」ってここではなんだっただろうか?
そう、bだったね。
つまりここでbの値に5が代入されたってことだ!

    printf("%d\n",*a);

aに*がついている。
これはポインタに格納されているアドレスに入ってるデータを示すんだから
ポインタに格納されているアドレスはbのアドレス、
で、bに先ほどアドレス渡しで5を代入したんだから
ここでは「5」が表示されるね。

    printf("%p\n",a);

aになにもついていない。
aはポインタ変数だから、アドレスが保存されているんだった。
上記でaには変数bのアドレスを格納したのだから
ここではそのまま変数bのアドレスが表示されるはず。

    printf("%p\n",&a);

aに&がついている。
これはaそのもののアドレス(aが指すアドレスではない!)を示すんだった。
なのでここではaそのもののアドレスが表示されるね。
ちょっと分かりにくいひとは
パソコンのファイルイメージではaはエイリアスだったことを思い出して。
&aはエイリアスファイルそのもののありかを示すんだった。

ちなみに僕のデバッグ環境(Mac OS X 10.6.1, GNU gdb 6.3.50-20050815)では
以下のように表示された。

5(←ポインタaが格納しているアドレスに格納された値 = bの値)
0x7fff5fbff6ac(←ポインタaが格納しているアドレス = bのアドレス)
0x7fff5fbff6b0(←ポインタaそのもののアドレス)

いかがでしょう?
少しでも理解の助けになれば幸いです。

【初心者向け】組み込みプログラムの学習に役立つサイト7選

思うところがあって書いた前のエントリが思いのほか好評だったので驚いた。
ブクマのコメントとか読んでると、僕が考えてきたことが間違っていないのだなと思って嬉しかった。
のでこのblogでは組み込みのことを書いていこうと思う。

というわけで僕が組み込みの勉強をはじめたときにリファレンスにしたサイトをまとめようと思う。
「なんでこれがないんだ!」みたいなものがあればコメントなどでお寄せください。
随時追加します。
特に僕はRTOSや組み込みLinuxについてはあまり知識がないので…

マイコン入門コース・基礎編

http://www3.toshiba.co.jp/semicon/member_semicon/micon_elearn/micon_intro/mic_intro_top.html
マイコンの基本的な動作とか機能についてのe-learning教材。
東芝のサイトだけど、ルネサスなどの他社マイコンでもこれを読めばOK。
マイコンってなによ?」ってところから解説してあるし
特に「マイコンの基礎機能(アーキテクチャの説明)」は初心者でも分かりやすく短文にまとめてある。

  • 割り込み処理
  • 優先順位
  • スタックとスタックポインタ
  • スタック
  • 割り込み処理の種類
  • ノンマスカブル割り込み
  • マスカブル割り込み
  • リセットとウォッチドックタイマ

あたりの組み込み特有の「割り込み処理」のところは通読するといいと思う。

エレキジャック: (連載)シリアル・インターフェース アーカイブ

http://www.eleki-jack.com/cat21/
マイコンと外部素子が通信する際の通信方式であるSPIとかI2Cについての解説。
素子間通信については組み込み門外漢だった人には全く新しい分野だと思うので押さえておくこと。
前のエントリでトランジスタ技術とかディジタル・デザイン・テクノロジは
初心者には難しいと書いたけど、特集によっては初心者向けのよいものももちろんある。
これはその好例と言えると思う。
SPIで検索すると、就職試験のSPI対策のページばかりヒットするのでうんざり…。

センサ道場

http://www.netdecheck.com/coffee_break/dojyo/index.html
タイトルではセンサの話を扱っているようだが
「プルアップ抵抗ってなんでいるんだよー!」とか
「結局トランジスタでなにがやりたいの?」とか
そういうちょっとした疑問にふわっと答えてくれるサイト。
「ちょろっとIbを流すと、ドカッとIcが流れる素子」とか
手書きのグラフとか回路図とかでなんかほのぼのしている。
東京ガスのサイトだってのが意外でした。

ラトックシステム PC オーディオ ブログ

http://blog.ratocsystems.com/pcaudio/
I2SとかS/P DIFとかでIC間で音声データをやりとりする人は必見。
(すみません僕がデジタルオーディオ屋なもので…)
特に
#20 Digital Audioの伝送について(I2S編)
http://blog.ratocsystems.com/pcaudio/2008/04/20-digital-audi.html
#23 Digital Audioの伝送について(S/PDIF編 その3)
http://blog.ratocsystems.com/pcaudio/2008/06/23-digital-audi.html
は今まで読んだ中で一番良くまとまっていて分かりやすい。

【改訂版】組込みソフトウェア開発向けコーディング作法ガイド[C言語版][C++言語版]

http://sec.ipa.go.jp/publish/index.html#emb
IPAの組み込み関係の本はあんまり面白くないし役立った試しがないのだけど
この本は通読しておくといいかもしれない。
特に「C/C++での」コーディング規約などを意識していなかった人にはおすすめ。
「こう書くと間違いが少ない」みたいなものを把握しておくのは無駄じゃない。
上記サイトからPDFがダウンロードできるのでそれで足りると思います。
どうしても本で欲しい人は買ってもいいし
ESECなどでIPAのセッションを聞いたらタダでもらえます。
初心者がETSSとかの本を読むのは時間の無駄なのでやめましょう。

オシロスコープ ラーニングセンター

http://www.tek.com/ja/learning/oscilloscope-tutorial/
テクトロニクスのサイトだけど、基本的な内容は各社一緒なのでこれを読めばOK。
何が出来るのか、どうすればいいのかということが分かりやすく説明してある。
登録が必要なのが玉にキズ。でも個人名でもダウンロードできるのでご安心を。
もしテクトロのオシロを持っている会社だったら誰かが持っていないかさがすのもありだと思う。
Love!テクトロ!

「組み込み」ならではの基礎知識 ――スタートアップ・ルーチンからハードウェアまで

http://www.kumikomi.net/archives/2003/05/10kumi.php
今までデスクトップで動くアプリケーションを作成していた人だと
学校で「Cではmain()から実行されますよ」と習ったので
初期設定などを見たいのにmain()からずーっと追っちゃって見つかんないって苦労をした人も少なくないと思う。
実際は"リセットベクタ"というアドレスを読みに行くんだけど…というくだりを説明してくれる記事。

以上のサイトに書いてあることはハードウェアマニュアルでは
「分かってること」として記載されているので
上記に記載してあることを頭においておけば理解も深まると思う。

今春“組み込み”プロ”グラマーになる人が、あと1週間とはいわないけどこれからやってほしい7のこと

今春“プロ”グラマーになる人が、あと1週間ですべき7のこと
http://hiroki.jp/2011/03/27/1767/

新入社員用のテキストをほそぼそと作ってるので
今日話題になった上記のエントリーはすごく参考になった。
ただどうしてもこの手のエントリーはWeb屋さんとかSIerとか向けのものが多くて
ゴリゴリした組み込み業界に足を踏み入れる人向けのエントリーが
なかなかないのが実情。

というか「普通の理系」でも
入社するまで組み込みってどんな世界かわからんのじゃないか。
僕もそうだった。

家電とかAV機器とか車とかケータイとか
「モノ」をつくる会社でプログラマで採用されたあなた、
あなたは間違いなく組み込みプログラマとして働きます。

というわけで自分なりに今春組み込み"プロ"グラマになる人向けに
組み込みプログラマ2年目の僕が思うことを綴ってみる。
ただし(Excel方眼紙に対してアレルギー反応がなくなるなど)
現場にかなり毒されている感があるので
「それはないだろー」的なツッコミがあるとうれしいです。

「僕はプログラマ採用されたんだ!」と思い込むのはやめよう。

仕事で組み込みプログラミングをやりはじめると
「僕はプログラマなのに、なんでこんなことをやるんだ!」って思うことがあると思う。

ここで忘れちゃいけないのはキミが動かすのはソフトウェアじゃない。ハードウェアだ。
キミが通信するのはこれからはサーバだけでなくて、
PLD/FPGAとかDACとかのICかもしれないし、別の外部機器かもしれない。
プログラマ」だけど回路図やプリント基板は絶対読めなきゃいけないし、
半田ごてでハンダ付けすることもあると思う。

プログラマだからと思い込んで
ハードウェアのことをおろそかにすると後々本当に苦労する。
「僕はプログラマなんだ」という先入観をもつのはやめて研修に臨もう。
ハードウェアもわかるプログラマが一番戦力になるし、転職をするときも一番有利。
「プログラムのことしかわからない組み込みプログラマは、ただのプログラマ」だよ。

大学の教科書を捨てない。

時期的に、もう手遅れかもしれないけど
まだ引越し荷造り中だとしたら、大学の教科書は捨てずに持っておこう。
特にデジタル信号処理とかフーリエ変換とか電気回路とか電子回路とか。
あと情報科学の分野のテキストも大事。
MOS-FETとかフリップフロップ回路とか
電気回路の内容が含まれている実験・演習の実験指導書もとっておこう。
いや、あの実験で使ったわざとらしい回路、実際に超使われてるんだってば!

C/C++の文法を確認しよう。

インターネットでプログラムとかアプリケーションの話題とか追っかけてると
華やか(に見える)Web業界で、みんながクールなWebサービス
PHPとかPythonとかRubyとかで作ってる話題を見ることが多いと思う。
僕も学生時代は簡単なウェブサービスとかつくって遊んでた。

ただ組み込みではほとんどの人がCかC++を使うことになると思う。
最近はJavaが動くマイコンも増えてきたけど、まだまだ少数派。
アセンブラは未だ全然現役。

Web界隈をずっとやってた人はCの言語仕様とか忘れちゃってるんじゃないかと思うし
そもそもちゃんと押さえていない人も多いと思う。
中途半端にプログラムかけちゃったりするせいで
結構分かってるフリしてるヤツが一番面倒臭いので
K&Rを読めとは言わないから
C/C++の文法とか言語仕様をちゃんともう一度確認しておこう。
特にポインターから逃げてた人、仕事にすると逃げられないよ。

ちなみにアセンブラを流したあとに
Cのポインタを考えると
「なんでこんなことにあんなに悩んでいたんだろう」と思うようになるよ。

Web系の言語を忘れていいってことじゃない。
その知識や経験は自作ツールを作ったりするときには大いに役立つから
引き続き伸ばすように。

コンピュータの基本動作概念をおさらいしよう。

組み込み初心者が組み込みプログラマになるからと言って
いきなり付け焼刃的に
トラ技とかディジタル・デザイン・テクノロジとかに手を出すと
何書いているか分かんなくて自信をなくすと思うのでやめたほうがいい。
(フレッシャーズ向け特集も全くの門外漢には結構レベルが高い)

まずはコンピュータ科学の教科書とかを使って
もっと基本的なコンピュータの動作概念をおさらいしよう。
キミが動かすだろうマイコンだってコンピュータなので基本は全部一緒。
よりハードに近い部分にアクセスするので、この知識は重要。
例えば
「メモリ空間」「ブート」「レジスタ」「アドレス」
についてきちんと説明できるだろうか?
代表的なレジスタにはどんなものがあるだろうか?

トラ技やディジタル・デザイン・テクノロジはそのあとでもOK。
まともな会社だったらきっと会社で購読してるはずだし
バックナンバーも揃えているはずだから、
落ち着いたら数年分のフレッシャーズ向け記事をまとめ読みするといいよ。
少なくとも何書いてるかは分かるようになるから成長も感じられると思う。

最強のデバッガ、オシロスコープ

組み込みプログラムの世界では、出力は画面に表示することだけじゃない。
(むしろ画面に表示を出せる局面でのデバッグは楽勝)
組み込みプログラマの一番基本的な出力は
マイコンの端子をHIGHにしたりLOWにしたりすること。
いわゆる"0"と"1"の世界を地で行くわけ。
あと不具合の原因が自分のソフトウェアだけが原因じゃなくて
ハードウェアの不具合であることもよくある。

そんな世界では開発環境を睨んでいても、バグの原因が見えないことがほとんど。
そんなときの味方がオシロスコープ
電子回路が今どういう状況かということを視覚化して見せてくれる最強のデバッガ。
なのでオシロスコープの使い方とか、何が出来るのかとかを復習しておこう。

ちなみに僕は大学時代に
アナログオシロを音声波形を見るために使った経験しかなかったので
会社に入って初めてテクトロニクスのデジタルオシロを使って驚いた。便利すぎ。

道具(PC,エディタ)を洗練させる。

これは「今春“プロ”グラマーになる人が、あと1週間ですべき7のこと」に
書いてある通り。
マイコン統合開発環境(HEWとか)のエディタは恐ろしく使えないので
使えるエディタを自分で整備できるようにしておこう。

僕は最初先輩社員に勧められて
(30,000円近い値段で、かつライセンス認証もある)MIFESを使用してたけど
今は結局Emacsに落ち着いた。

自分の近くで行われるプログラマが参加するイベントを押さえておこう。

組み込み界隈から見ると
Web系の人はいろんな勉強会とかイベントをやってて非常に羨ましいもの。
組込み系の勉強会とかはめったに見ない。残念だけど。
ただし組み込みプログラマでもプログラマプログラマ
自分の興味のあるイベントを探して参加してプログラマとしての交流を続けよう。
特に組み込み業界に長くいる先輩社員にはそういう習慣がないので
自分で探すしかない。

もしキミが関東で働くならMake: Tokyo Meetingはハズしちゃいけない。
どうにか都合をつけて参加しよう。

最後にひとこと

上にもちょっと書いたけど
組み込みをやりながらWeb系界隈を見ていると
なんか華やかで羨ましくなることがあると思う。
僕もそうで、PHPの勉強会とかに顔出して
みんなが新しい技術とかフレームワークを使っているのを見て
ものすごく時代遅れの業界にいる気分になって、すごく寂しかった。
自動テストとかがなかなか出来ない業界だし
開発手法もウォーターフォール一辺倒だし。
アジャイルとか憧れるけどどう導入すればわかんないし、
CだからUMLとか導入しづらいし。

けど音が出たりとかハードウェアが実際に動くようになると一気に面白くなる。
ただモノが動くようになるまでの間にはすごく時間がかかるんだけど。
ブレークスルーする瞬間がかならず来るので
それまでは諦めずに経験を積むことをおすすめします。

あのガジェットも、組み込みプログラムがないと動かない!