たのしい工学

プログラミングを学んで、モノをつくりたいひと、効率的に仕事をしたい人のための硬派なブログになりました

【独学するコンピュータサイエンス】関数と型

   

関数型の型定義

関数型も型ですから typedef による別名定義が可能です。慣れないうちは分かり難いと思いますが慣れてしまえば簡単で、 int 型に別名を定義する感覚と同じになる事でしょう。
次のプロトタイプ宣言を見てください。

double func( int a, char * s, size_t sz );
これは「 double ( int, char *, size_t ) 型」の宣言です。
この型の変数 f0 を宣言し func にて初期化記述するとこうなります。

double ( * f0 )( int a, char * s, size_t sz ) = func;
関数を特徴付ける引数の変数名は略せますがプロトタイプ宣言に合わせ付けてあります。この型を typedef 定義し、変数の宣言と初期化の同時記述を行います。

typedef double Tf( int a, char * s, size_t sz );
Tf * f1 = func;
Tf は double ( int, char *, size_t ) 型の別名ですからその変数は Tf * f1 となります。もしポインター宣言子 * も含めて typdef 定義するならば

typedef double ( * Tf2 )( int a, char * s, size_t sz );
Tf2 f2 = func;
となります。 Tf2 は double (*)( int, char *, size_t ) 型の別名なのでこれで良い事になります。

関数のリンケージ

少し説明しましたが関数にもリンケージは存在します。関数に無リンケージはありません。内部リンケージ若しくは外部リンケージが存在するだけです。
外部リンケージにするには extern 指定を、内部リンケージにするには static 指定をします。省略時は extern 指定されたものと見なされます。
例を挙げます。

void func( void ); /* プロトタイプ宣言/
void func( void ) /
関数定義 */
{
return;
}
これは次の様に記述されたものと同じになります。

extern void func( void ); /* プロトタイプ宣言/
extern void func( void ) /
関数定義 */
{
return;
}
つまりこれまで作成した関数の殆どは外部リンケージだったのです。
内部リンケージにするには static を明示的に指定します。

static int f( int a ); /* プロトタイプ宣言 /
static int f( int a ) /
関数定義 */
{
return ( a + 1 );
}
この他の点についてはオブジェクトに関するリンケージと同じです。

関数のリンケージはとても重要です。あるソース・ファイルを一つの機能を持つ関数群から成るとします。そのソース・ファイル内だけで使用する関数は static 指定、他のソース・ファイルからも使用する関数は extern 指定又は省略します。 static 指定をした関数名はそのソース・ファイル内だけで有効になるので関数の隠蔽が出来ますし、関数名の衝突も起こり難くなります。
この時注意する点は、外部リンケージの関数のプロトタイプ宣言や変数等と、内部リンケージの関数のプロトタイプ宣言や変数等を、同一ヘッダー・ファイルに記述しては意味が無いという事です。外部リンケージ専用のヘッダー・ファイルと内部リンケージ専用のヘッダー・ファイルにそれぞれ分けなくてはいけません。
外部リンケージの関数や変数は他のソース・ファイルでも使用します。ですからそれらのソース・ファイルでは外部リンケージだけが記述されたヘッダー・ファイルをインクルードします。実際に関数を定義するソースでは、外部リンケージ専用のヘッダー・ファイルと内部リンケージ専用のヘッダー・ファイルの両方をインクルードします。
これにより内部リンケージのオブジェクトが他のソース・ファイルから見えなくなり、完全に隠蔽が行われた事になります。
今までこれを行わず同一ヘッダー・ファイルに外部リンケージと内部リンケージを混在させていましたが本来はしてはいけません。折角内部リンケージにしても、ヘッダー・ファイルをインクルードしたソースでは内部リンケージの関数や変数が丸見えになってしまうからです。

main 関数とその引数

main 関数は次の型、或いはそれに適合する型でなければなりません。

・戻り値は int 型。
・引数は無し、或いは第一引数が int 型で尚且つ第二引数が char *[] 型。

つまり

int main( void );
又は
int main( int argc, char * argv[] );
の二つ及びそれに適合する型に限られます。他の記述が許されてもそれはコンパイラー独自の拡張形式です。引数の名前は任意ですがこの名称が一般に用いられます。
これまで main 関数の引数は void でしたがこの様に引数を受け取る事も可能です。二つの引数はどこから渡されるのでしょうか。大雑把に云えば OS です。

今回はここまで

 - コンピュータサイエンス