*C言語 アセンブリから派生した言語の一つで、機械語に近いアセンブリに対して、人が見やすい言語として開発された。 今ではプログラムの中心として用いられることが多く、発展型としてC#、C++など別のものに特化させたものがある。 今ある言語の基本的な部分はC言語と同じなので、C言語を理解しておくと、それなりのプログラムが読むことができるようになる。 はずであるが、人間に近すぎて逆に難しい言語でもある。 よく言われるのが、書き方。 ターミネータ(セミコロン)により、文節という概念がさらに細かくなり、文字列中でなければ、改行、スペース使い放題である。 例 ---- if( a==0 ) { a++; b++; } ---- if(a==0){a++;b++;} ---- if(a==0){ a++; b++; } どれも同じ意味をあらわすが、大事なのは読みやすさでもある。 ここでは、使い方から、読みやすいプログラムまで、順を追って説明していきたい。 *構文 プログラムの構文は次の通り。これはC言語に限らない。 :順次構文|最も基本的な構文で、上から下に一行ずつ処理していく。 :分岐構文|条件によって分岐し、行う処理と行わない処理に別れる。 :反復構文|特定のところまで戻り、再び同じ作業を行う。 これらをうまくつなぎ合わせて、プログラムを作る。 フローチャート作成を行うことで、最も適切なプログラムを作成できる。 *命令 プログラムは命令の集まりである。 プログラムにおける命令とは、特定の動作、作業をさせるもので、計算から画面の表示までいろいろな命令がある。 ちなみに、C言語の命令の中で最も多く使われる記号は=(イコール)で、意味は代入である。 命令はターミネータ(;)で区切って使用する。つまり、ターミネータの数は命令の数に等しくなる。 命令の例 :A=A+B;|AにA+Bの結果を代入する。決してAがA+Bに等しいわけではない。 :init();|initという関数を実行する。関数については後ほど。 *全部使えてナンボなものたち **分岐、反復など if(条件文) else switch(判断文) case 定数: break while(条件文) for(初期分;条件文;繰り返し文) **演算子 = ++ + += -- - -= & | >> << ! ^ **条件式 == != < <= > >= && || *関数 ある一定の命令を集めた命令で、そこに引数と戻り値があることから関数と呼ばれる。 main関数内で用いるためには、その上に関数の内容を書くか、先に宣言をしておいてあとで書く方法がある。 例外を除いて好きな名前をつけることができ、何度も呼び出して実行させることが出来る。 雰囲気は次の通り。 int max(int x, int y); main(){ ... c=max(a,b); ... } int max(int x,int y){ ... } 関数を使うメリットとして、 -main内がすっきりする -同じ作業を一つにまとめられる -複数行にわたるコメントアウトを省略できる 何度も使うものは、関数として宣言しておくとよい。 *マクロ C言語には、マクロと呼ばれる様々な機能が用意されている。 マクロはソースに記述するものの、直接プログラムになるものではない。 コンパイル時に読み込まれ、プログラムに影響を与えるものである。 ちなみに#で始まるものがマクロである。 例えば、 :#include<stdio.h>|stdio.hというファイルを読み込む :#define K 10|Kを10に置き換えてコンパイル など。 コンパイラによって依存がある場合があるが、マイコンでは関数や機能の設定に用いられることもある。 *コメント 他人に読まれることがあるプログラムで、最も大事なのはコメント。 コメントは、コンパイラやアセンブラを通るときに無視され、動作には全く影響を与えない。 プログラムなどの文を残しておきながら実行させないようにするためにコメントにすることを、コメントアウトという。 コメントアウトする方法は次の通り。 行の最初に//(スラッシュ、スラッシュ)を挿入する /*(スラッシュ、アスタリスク)と*/(アスタリスク、スラッシュ)で囲む この中に書くのは、プログラムと直接関係ないことでもかまわない。 例えば、ピン配置や計算の式や結果など。 特に開発者、プログラムの内容と更新日は入れておくべき。 わかりにくい構文も、いれておくべきだがいれにくい。 コメントが入っていないプログラムを他人が読むと苦痛。 *ところで C言語がわかっている人は、次の3通りが同じ意味を成すことがわかる。 a++; a+=1; a=a+1: 何にも考えなければ、これはどれを使っても答えは一緒である。 **だしかし あ、だがしかしってことね **実はまったく違ったのである。 (ただし、例外を含む) 次の3つのアセンブリを見てくれ。 INCF main_a_L0,1 BTFSC STATUS,Z INCF main_a_L0+1,1 MOVF main_a_L0,0 ADDLW 1 MOVWF STACK_0 MOVLW 0 BTFSC STATUS,C ADDLW 1 ADDWF main_a_L0+1,0 MOVWF STACK_0+1 MOVF STACK_0,0 MOVWF main_a_L0 MOVF STACK_0+1,0 MOVWF main_a_L0 INCF STACK_0,1 BTFSC STATUS,Z INCF STACK_0+1,1 MOVF STACK_0,0 MOVWF main_a_L0 MOVF STACK_2+1,0 MOVWF main_a_L0+1 これは、先ほどの3つをコンパイルし、出力されたアセンブリファイルである。 順番しだいで少々長さは変わるが、ほぼ一緒と思ってもらっていい。 アセンブリがわからない人でもわかるように言うと、 **アセンブリは行の数が実行する時間である。 となる。つまり、同じ処理をするためにかかる時間が、書き方によって違うのである。 驚いたのは、a+=1よりもa=a+1のほうが時間が短いこと。 ここで注意すべきは、今回は1を足したことで、2以上ならインクリメントは使えなくなるため、また必要な時間は変わってくる。 おそらくa+=2はa=a+2よりも短いと考えられる。実際に試してみると面白いかもしれない。 このようなことが、他にも多数ある。(if(a==0)とif(!a)など) いろいろ探して、プログラムを改良してみると面白い。