C言語の文法の基礎を解説します。今回は基礎ということで、Cの基本構造の解説で す。
Cではプログラムの書き方に特に制限はなく、式を複数行にわたって書くことも許されています。 そこで、プログラムはなるべく見やすく書くことを薦めます。 これは、デバッグをする時にも関係してきます。一行に複数の文を書くとどの部分でエラーが出たのか わかりにくくなりますから。
void main(){printf("Holy Up!\n");}と書いてもvoid main() { printf( "Holy Up!\n" ) ; }と書いてもコンパイルした結果は同じになります。 自分なりに字下げの規則を決めておくのがいいでしょう。
C言語は主に、「式」「文」から成り立っています。また、プログラムを書く上で、 「変数」「データ型」「関数」「制御構文」が重要となります。それぞれについて説明 していきます。
「式」
値を持ったもの。C言語における意味を持つ最小構成単位。式は単独でプログラム中 に置くことは出来ない。また、式を評価(計算)し結果が0以外になったときを「真」、 0になったときを「偽」とする。
例b=1+2 a 1 sin(pi()/2) "X680x0" a>b「文」
式の最後にセミコロン「;」をつけると文になる。単独でプログラム中に置くことが出来る。 また中括弧「{}」内に複数の文を書いたもの(複文)も一つの文とみなされる。
例b=1+2; a; 1; sin(pi()/2); "X680x0"; a>b; {a=2*x+y;b=2*x-y;} ;「変数」
変数は任意の値を格納しておくための箱のようなもので、使用するためには格納出来るデータの種類と、 変数の名前を宣言する必要がある。
変数の名前に使える文字には英大小文字、数字、アンダーバー「_」、全角文字(日本語拡張時のみ)がある。 ただし名前の先頭に数字は使えない。
変数は各ブロック(中カッコ"{","}"で囲まれた範囲)の先頭で定義することが出来、 有効範囲は定義したブロックの中だけである。
「データ型」
Cでは様々なデータ型を扱うことが出来る。以下に、その種類の一部を挙げる。
整数型 char 符号付き8ビット整数(-128〜0〜127) unsigned char 符号なし8ビット整数(0〜255) short 符号付き16ビット整数(-32768〜0〜32767) unsigned short 符号なし16ビット整数(0〜65535) int 符号付き32ビット整数(-2147483648〜0〜2147483647) unsigned int 符号なし32ビット整数(0〜4294967295) long int intと同じ unsigned long int unsigned intと同じ 実数型 float 32ビット実数(10-37〜1038) double 64ビット実数(10-307〜10308)
一般に、サイズの小さいもののほうがメモリ消費も少なく演算速度も速くなる。
「関数」
数学的な意味の関数は「何らかの入力に対して唯一の結果を返す」ものだが、C言語では、 それ以外に「画面に線をひく」などの数値を返す以外の副作用をもたらすものも関数と呼ぶ。 これを数学的な関数と区別して「手続き」と呼ぶこともある。
C言語は関数の集合体である。C言語のプログラムはmainという名前の関数の先頭か ら実行されるのである。
関数はライブラリによって供給されるものや、自分で定義するものもある。
関数は値をもつものなので、式になれる。
例cos(x) sqr(a)+b printf("%d,%d\n",x,y) line(0,0,255,255,15,'NASI');「制御構文」
繰り返しや、条件判断など、プログラムになくてはならないもの。処理の流れを制御する。 代表的な構文を以下に挙げる。
for(初期化式;条件式;ループ式) 文
最初に一度だけ初期化式を実行し、条件式が真の間、ループ式を評価し文を実行する。
if(条件式) 文1 else 文2
条件式が真であれば文1を実行し、そうでなければ文2を実行する。
while(条件式); 文
条件式が真の間、文を繰り返し実行する。
do 文 while(条件式);
文を実行してから条件式を評価し、真の場合、再び文を実行する。
switch(式) { case 定数式1: 文1 case 定数式2: 文2 case 定数式n: 文n default: 文 }式を評価し、定数式のいずれかに一致した場合、それ以降の文を実行する。 一致しなかった場合、default以降の文を実行する。
break;
ループから抜け出す。do-while文、for文、switch文、while文のなかにしか置くことは出来ない。
continue;
ループ内のcontinue文以降の処理を行なわずに終了条件チェックに処理を移す。 for文、do-while文、while文のなかにしか置くことは出来ない。
goto ラベル;
ラベル: 文
処理を無条件にラベルで示される文に移す。あまり使われない。
return 式;
関数をそこで終了させ、式を戻り値として呼び出し元に復帰する。式を省略すると、 戻り値は不定となる。
えー、以上がC言語で重要な要素の一部です。ではサンプルプログラムを示して、 それについて解説していきます。
================== sample02.c ================== 1: #include <graph.h> 2: #include <mouse.h> 3: #include <iocslib.h> 4: #include <doslib.h> 5: 6: void main_loop(unsigned short p) 7: { 8: unsigned short c; 9: int mx,my,dx,dy,bl,br; 10: c=p; 11: do { 12: mspos(&mx,&my); 13: msstat(&dx,&dy,&bl,&br); 14: if(br) c++; 15: if(bl) pset(mx,my,c); 16: } while(!(BITSNS(0)&2)); 17: } 18: 19: void main(void) 20: { 21: C_CUROFF(); 22: CRTMOD(12); 23: G_CLR_ON(); 24: mouse(4); 25: mouse(1); 26: main_loop(0); 27: KFLUSHIO(0xff); 28: mouse(0); 29: mouse(2); 30: C_CURON(); 31: } ==================================================
さて、このサンプルは一体何かというとグラフィックエディタです。マウスを使い、 左ボタンを押すと点を打ち、右ボタンで色の変更です。ESCキーで終了することが出来ます。
落書きにも使えませんが、普通の解説書に載っているようなサンプルでは面白くもなんともないので 視覚に訴えるようなプログラムにしてみました。
このサンプルをコンパイルするにはXCライブラリが必要です。コマンドラインで
gcc sample02.c -lbas -liocs -ldosと打ち込んでください。
先に書いた通り、C言語のプログラムはmain関数の先頭から実行されるので、 このサンプルでは19行から処理が始まります。
1〜4行は「#」で始まっています。これはプリプロセッサ命令といって、 コンパイラがソースを解析する前に、プリプロセッサによって展開されます。 この場合は「<>」で囲まれた名前のファイルを環境変数includeで表されるディレクトリから読み込み、 その位置に埋め込みます。
カレントディレクトリから読み込む時は「""」で囲んでください。
インクルードファイルには関数の使い方が書かれており、 コンパイラはこの内容と使い方があっているかどうかの確認もしてくれます。
6〜17行は関数main_loopを定義している部分です。 7行の中括弧から17行の中括弧の間が関数main_loopの実体となります。
6行では関数の名前、引き数、戻り値を定義しています。定義部分の書式は
[戻り値のデータ型] [関数の名前]([引き数リスト])となります。関数main_loopはunsigned short型の引き数をひとつ持ち、 戻り値を持たない関数です。よって
void main_loop(unsigned short p)のように定義しています。ここで定義された変数pは関数main_loop内でのみ参照出来ます。 また、pの内容を変更することも許されています。
8,9行は関数main_loop内で有効な変数を定義しています。関数の外(例えばmain関数内) ではこの変数は使えません。また、関数main_loopが終了した時点で変数は全て消え去ります。 再び呼び出されても、以前の内容は残っていません。
10行で変数cの初期値として、引き数pの内容を与えています。8行の定義と同時に 代入することも出来ますが、コンパイラによります。
11〜16行はdo-while構文を使っています。終了条件はESCキーが押されたかどうかです。 押されていない場合12〜15行を繰り返し実行します。
12行のmsposの引き数は変数の前に&がついています。今回はくわしく説明しませんが、 msposはこういう形で引き数を指定すると、そこに値を入れてくれる関数なのです。 ここではmxにマウスのX座標、myにマウスのY座標を入れてくれます。
同様に13行もdxにマウスのX方向の移動量、dyにマウスのY方向移動量、 blにマウスの左ボタンの状態、brにマウスの右ボタンの状態を入れてくれる関数です。
14,15行はif文です。14行の条件はbrが0でない時です。brは13行の関数で 右ボタンが押されていたら-1、離されていたら0が入るので、右ボタンが押されていた時、 c++が実行されます。
15行の条件はblが-1の時で、結局14行と同じになります。メモリ効率は14行の 方がよくなります。
14行のc++は変数cに1を加えて、それを新たなcの値とする式です。BASIC風には
c=c+1という意味です。
変数cは8行で定義した通り、unsigned short型なので変数のとれる値は0〜65535 までになります。では65535に1を加えるとどうなるか。 BASICではオバーフローを起こしてエラー終了してしまいますが、Cでは0になります。 逆に0から1を引くと65535になります。これをうまく使うとプログラムを簡略化することも出来ます。
このプログラムでは変数cをカラーコードに使っているので65535を越える数値は指定 出来ません。よって、65535を越えないようにしなければなりません。 が、プログラム側で何もしなくとも、65535の次は0になります。
15行のpset(mx,my,c)は座標(mx,my)にカラーコードcで点を打つ関数です。 これは特に説明の必要はないでしょう。
16行はdo-while構文の終了条件をチェックしています。条件は!(BITSNS(0)&2)となっています。 関数BITSNSはキーコードグループのキーの押し下げ状況をビットフィールドで返します。 ESCキーはグループ0に含まれるので引き数に0を指定しています。
BITSNSの1ビット目が1のときESCキーが押されていたことになります。
ここで使われている&は論理演算子です。
論理演算とは数値を2進数で表した時の各ビットについて計算することです。 論理演算には、論理和、論理積、排他的論理和などがあります。
論理和 0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1 10 | 12 = 14 (10進数) 1010 | 1100 = 1110(2進数)論理積0 & 0 = 0 0 & 1 = 0 1 & 0 = 0 1 & 1 = 1 10 & 12 = 8 (10進数) 1010 & 1100 = 1000(2進数)排他的論理和0 ^ 0 = 0 0 ^ 1 = 1 1 ^ 0 = 1 1 ^ 1 = 0 10 ^ 12 = 6 (10進数) 1010 ^ 1100 = 0110(2進数)
さて、16行の論理演算は論理積です。2を2進数で表すと00000010です。つまり、 BITSNS(0)&2でBITSNSの戻り値の1ビットが立っていれば、式の値は真(0以外)、 立っていなければ偽(0)になるというわけです。
16行の式の先頭には「!」がついています。これは式の真偽を逆にするものです。 ESCキーが押されていない時ループさせたいので、押されていない時を真にするために 使っています。
19〜31行はmain関数の定義です。C言語のプログラムにはかならず main関数がひとつだけ存在しなければなりません。 C言語のプログラムはmain関数の先頭から実行されるためです。
あとは21〜30行まで順番に関数を実行していくだけなので説明はいらないでしょう。 それぞれがどんな動作をするのかは自分で調べてみましょう。
最後に資料として演算子を載せておきます。
C言語演算子一覧
ひとつの式に複数の演算子が現れた場合、優先順位の高いもの(数字の小さいもの)か ら先に評価されます。同じ優先順位の場合は左から先に評価されます。
優先順位 1 ()
[]
.
->演算順序優先指定
添字
構造体メンバ指定
構造体メンバ間接指定優先順位 2 !
~
-
++
--
*
&
(型名)
sizeof真偽の反転
ビット反転
マイナス
インクリメント
デクリメント
間接演算子
変数などのアドレスを得る
キャスト
変数などのサイズを得る優先順位 3 *
/
%乗算
除算
剰余算優先順位 4 +
-加算
減算優先順位 5 >>
<<左ビットシフト
右ビットシフト優先順位 6 >
<
>=
<=大きい
小さい
以上
以下優先順位 7 ==
!=等しい
等しくない優先順位 8 & ビット論理積 優先順位 9 ^ ビット排他的論理和 優先順位 10 | ビット論理和 優先順位 11 && ビット論理積 優先順位 12 || 論理和 優先順位 13 ?: 三項演算子 優先順位 14 =
+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=代入
a=a+b
a=a-b
a=a*b
a=a/b
a=a%b
a=a>>b
a=a<<b
a=a&b
a=a|b
a=a^b優先順位 15 , 逐次評価