|
|
2. 関 数
では前回の hello.c のコードを見ていきましょう。
1行目:
#include < stdio.h >
#include はそのあとに指定されているファイルをその位置に読み込みます。この1行目の場合には stdio.h というファイルを読み込んでいます。この読み込みはコンパイルと呼ばれるソースコードファイルを機械語に翻訳する作業の前に行われます。このようにコンパイル前の準備段階として行われる作業のことを「プリプロセス」と呼びます。また、この stdio.h のように拡張子「.h」の付いたファイルは「ヘッダファイル」と呼ばれ「関数」や「クラス」の宣言や定義がされています。(関数については後ほど説明します。クラスは C言語には出てきません)。
この hello.c プログラムのソースコードでは4行目の printf 以外はすべて C言語の基本的な文法として最初から言語仕様の中に組み込まれている単語や記号です。ところが printf はC言語にとっては(もしくは C言語のコンパイラにとっては)未知の言葉なのです。もしコンパイルの途中でこのような未知の言葉に出会うとその場でコンパイルは中止されてプログラムは完成しません。そこで printf の宣言や定義をしている stdio.h をソースコードの最初に読み込んでおき「printf」という言葉をコンパイラに知らせておくことで hello.cプログラムを無事にコンパイルすることができるようになります。
なお stdio とはスタンダードインプットアウトプット(標準入出力)の略で、コマンドラインで入力や出力をする多くの関数の宣言や定義がされています。また stdio.h が < > と山括弧で囲まれているのは、stdio.h がコンパイラ開発者(もしくはコンパイラ販売者)が最初から用意したヘッダファイルで、ある特定の場所に収められていることを表しています。自作のヘッダファイルの場合にはプログラムファイル(.cファイル)と同じ場所に保存して "xxxxxxx.h"とそのパス名で場所を表します。
なお、前回 gcc というコンパイルを指示するコマンドを GNU C Compiler の略だと紹介しましたが、
GNU Compiler Collection の略が正しいみたいです。
3行目: int main( void ) {
ここで今回のテーマである「関数」が登場してきます。関数とは何かの作業をする手続きのことで、言語の種類によって関数・メソッド・プロシージャー・ルーチンなどさまざまな呼び方がされています。C言語では関数と呼ばれ Objective-C言語ではメソッドと呼ばれています。要は何かの仕事(作業)を関数の中に記述して(関数という単位にまとめて)、その関数を呼び出すことによってプログラムを進めていこうというものです。
特にこの main 関数はC言語とObjective-C言語ではプログラムが起動すると最初に呼び出される関数と決まっており必ず必要な関数となります。そしてこのような意味合いを持つ関数なので printf 関数とは違いヘッダファイルをわざわざ読み込む必要もありません。
関数は、 戻り値の型 関数名 ( 引数1, 引数2, 引数3 ) という形で記述されます。
戻り値の型とは、関数は何かの仕事をしてその結果を返す場合があります。その場合、その返ってくる結果がどういう型で返ってくるのかを指定します。3行目の main 関数では int という型で結果が返ってくることになっています。int とは整数という意味で、結果として整数が返ってくることを表しています。なおこの「型」については後の回で「データ型」としていろいろな型についてあらためて説明します。
戻り値の型のあとにスペースを空けて main と関数名が記述されます。プログラミングをはじめたばかりのころはどこにスペースを入れて、どこにスペースを入れてはいけないのか分かりずらいと思いますが、単語の切れ目には当然スペースが入ります。もし intmain と続けてしまうと全く新しい単語になってしまいます。またスペースの数は1個でも複数でも同じ1スペースとして解釈されます。またタブや改行もスペースと同じ意味になります。また逆に「 ma in 」と単語の途中でスペースを入れてしまうとそれもまったく新しい単語になってしまいエラーとなります。
main 関数の後の引数を現す記号 ( ) は main() と続けても、main ( ) とスペースを空けてもどちらでもかまいません。どちらにしても意味はコンパイラに通じるからです。
( ) の中には関数に仕事(作業)をしてもらう時に必要なデータを入れます。例えば2つの整数を足した結果を返してもらう関数には sum ( 数字1, 数字2 ) などと足してもらいたい2つの数字を ( ) の中に書きます。この ( ) の中に書かれた値のことを 引数 と呼びます。引数が複数ある場合はカンマ( , )で区切ります。引数が不必要な場合は ( ) と空のカッコを書く事もできますし、 ( void ) とすることもできます。 void とは何もないことを表す単語です。
関数は、例えば int main( void )で一応宣言されたことにはなりますが、関数に実際にやってもらう作業は {    } の中に記述します。
3行目から6行目を見て下さい。3行目の終わりに { があり、6行目のはじめに } があります。そしてその間の4行目と5行目に2つの文がかかれています。この2つの文(プログラミングの中では文も式と呼びます)が main 関数が実際に行うことです。C言語には「行」や「文の終わり」という概念はありません。4行目や5行目のように必ずセミコロン( ; )で1つの実行式を終らせなければなりません。
この { と } で囲まれた文のことを「ブロック文」と呼びます。
4行目: printf ( "Hello World !\n" ) ;
stdio.h のなかで定義されている printf 関数を呼び出しています。関数の呼び出しはこのように 関数名 ( 引数 )と記述します。その関数に戻り値があるかどうかは呼び出しの時に記述する必要はありません。printf 関数は書式を指定してコンソール(ターミナル画面)に文字を出力する関数です。あらかじめ用意していた文字列を表示することもできますし、4行目のように " と " の間に文字を入れることによってその文字を表示することもできます。
ここで注意していただきたいのは、"Hello World !\n" の最後の \n の部分です。この \ (バックスラッシュ)で始まる何文字かの文字列はエスケープ文字列と呼ばれ、特殊な目的のために使用されます。今回の \n は改行を表しています。試しにこの \n を削除して(間違って最後の " まで削除しないで下さいね)コンパイルして実行してみてください。どのように表示されるでしょうか?
5行目: return 0;
ここでこのプログラムを終了しています。return とは呼び出し元に返るという意味です。Bという関数がAという関数から呼び出されていれば return で B関数を終了してA関数に制御が戻ってきます。しかし今回の場合は最初に呼び出される main関数から return されています。main 関数の呼び出し元とはどこになるのでしょうか? そうです。main関数の呼び出し元はオペレーティングシステム( OS )ということになります。OS に制御を戻す、つまりプログラムを終了するということになります。プログラムは main 関数で return に出会うか、main関数の最後の } (ブロック文の閉じる)に出会うと終了します。その他にもexit( )関数で main 関数以外からでも終了させることができます。なお exit( )関数を利用するには stdlib.h の #include が必要となります。
関数には引数の有無に関わらず必ず( )が付きます。今後、関数を表すときには関数名( )と記述することにいたします。
ここでは return で 0 という整数を返しています。main( )関数は int (整数値) を返すことになっていたのを覚えていますか?。通常プログラムでは終了時に 0 が返ってくれば正常に終了したとみなされます。0以外の数値が返ってくれば異常終了した可能性が高くなります。アプリケーションを使っていてそれが突然終了したときに「アプリケーションxxxxxは原因不明の理由で終了いたしました。」というアラートをご覧になったことがあると思います。これはアプリケーションの終了時に返って来る数値をチェックしているのです。
自作関数
では、関数を自作して使ってみましょう。
funcA( )とfuncB( )について警告はでますが、一応コンパイルができ実行もできるみたいです。これはXcodeのコンパイラが優秀すぎるだけの話で普通はこの func1.c は、funcAやfuncB関数をはじめて使う以前に定義がなされていないのでエラーが出てコンパイルできません。そこでエラーの出ない(警告の出ない)ソースコードに変えてみます。
この形だとコンパイラも文句はないみたいです。しかしこのように単純な例は別として、普通はすべての関数をはじめて使う以前に定義するというのは無理な話です。そこで次に説明する「プロトタイプ」という手法が使われます。
プロトタイプ
プロトタイプとは、それぞれの関数のシグネチャ [ 戻り値 関数名 引数 ]の末尾にセミコロン( ; )を付けたものをプログラムの冒頭に記述したものを言います ( 3行目と4行目 ) 。未知の関数の定義をコンパイラに事前に知らせるという意味では stdio.h などのヘッダファイルと同じことしているのだと思って頂いて結構です。実際に stdio.h などのヘッダファイルの中身を見ると、このプロトタイプが数百行並んでいます。
ターミナル上のコンパイルでもコンパイラは何も文句を言ってきていません。
なお、今までは実行ファイルはすべて a.out という名前でコンパイルしてきましたが、今回からは3行目のように -o オプションを付けて、実行ファイルの名前を指定するようにいたします。今回は func という実行ファイル名でコンパイルいたしました。今後はこのようにひとつひとつ違う実行ファイル名をつけていきましょう。
お疲れさまでした。これで第2回は終ります。次回は変数とデータ型について掲載したいと思います。
|
|
|