宣言 - みる会図書館


検索対象: C言語によるプログラミング 基礎編 第2版
74件見つかりました。

1. C言語によるプログラミング 基礎編 第2版

9.5 ユーサ定義型 ユーザ定義型として、構造体、共用体、 typedef 、列挙型を見てきましたが、これらは文法上共 通する点があります。それは、宣言と定義という 2 つの手続きが必要であるということです。なぜ、 2 つの手続きが必要かを調べる前に、まず宣言と定義の違いをはっきりさせておきましよう。 まず、定義とは何でしよう。「定義」とは、ある変数に実際のメモリを割り当てるマ 33 ことをいい ます。よく「実体を取る」とか「領域を確保する」などというのは「定義」を指しています。 一方、「宣言」とは、ある変数をどのような型で使用するかをコンパイラに知らせるだけで、実 9.5.3 際にメモリは割り当てられません。 《ソースプログラム》 【定義】 s truc t tag char S ′・ struct tag my_data : - 《コンバイラ》 - struct tag のサイ ズが 1 バイトであること を認識する my—data 用の 1 バイ トの領域を確保する ・図 9.7 宣言と定義の違い 《メモリイメージ》 00F0 00F1 00F2 00F3 00F4 宣言と定義を同時に行えば、型の情報がコンパイラに伝わると同時に、変数の領域がメモリ上に ことは、「宣言」と「定義」に違いがあることと、実際のプログラムを読んで「宣言」と「定義」 ーこで学んでいただきたい 「変数は使用する前に必ず宣言すべき」という具合に書かれています。 の用語は完全には使い分けられてはいません。また、多くの C に関する書籍でも「変数宣言」とか 文脈によっては宣言と定義を明確に分離して記述できないときもあります。本書の中でも、これら ユーザ定義型に限らず、 C において宣言と定義の違いを理解することは非常に重要です。しかし、 山です。 ラに示さなければなりません。これが、ユーザ定義型において明示的な宣言が必要であることの理 らもっているわけではありません。そこで、ユーザ定義型では「宣言」として型の詳細をコンパイ 義した新しい型についての情報 ( たとえばそれがどのくらいのメモリを必要とするのか ) をはじめか かれていました。ユーザ定義型はプログラマが自山に作成する型なので、コンパイラはユーザが定 さて、ユーザ定義型に話を戻しましよう。ユーザ定義型では、宣言と定義の手続きがはっきり分 ません。すなわち、宣言されただけの変数は、実体がないということです。 確保されないのです。プログラムの世界では変数の居場所はメモリ ( レジスタも含む ) 上にしかあり 確保されます。しかし、前述のように、宣言しただけでは変数のための領域はメモリ上のどこにも を読み分けることが重要であるということです。 マ 33 自動変数は、実行時にスタックやレジスタに変数を確保しますが、 いう表現をします。 こではそれらを含めて「メモリを割り当てる」と 323

2. C言語によるプログラミング 基礎編 第2版

5 章 関 これまでは、 ANSI 規格のコンパイラに関する関数のプロトタイプ宣言と定義について学んでき 数 り、関数定義の中に引数の型を宣言するとコンパイルエラーとなりますので、次のように宣言 / 定 関数のプロトタイプ宣言の中に、関数の引数の型とその名前を宣言するとコンパイルエラーとな ましたが、 ANSI 規格以外のコンパイラを使用する場合ⅵ 6 、以下の点で異なります。 義することになります。 ANSI 規格のプロトタイプ宣 int powint (int x ′ int ・ ANSI 規格の関数定義 int powint (int x, int リスト 5.8 非 ANSI コンバイラでの関数宣言と定義 #include く s セ d 土 0 . h> 古いコンバイラ ( 非 ANSI) のプロトタイプ宣 int powint ( ) ー 古いコンバイラ ( 非 ANSI) の関数定義 int powint (), p) int x; int p; int powint ( ) ー int main ( void ) return y ー while( p- int y = 1 : P ー X : int powint ( x, p ) return 0 ー 土 n セ int > 0 ) ←関数のプロトタイプ宣 ←関数の定義 ←引数の型宣言 ←引数の型宣言 さて、以下のプログラムは、 powint という関数を main 関数の前でプロトタイプ宣言 ( 引数名を省 略 ) し、 main 関数の後で定義することによって 20 から 210 まで 1 ずつ増して 2 のべき乗を求めていま す。今まで説明した内容をすべて取り込んだ完全なプログラムです。 マ 16 170 現時点ではほとんどありませんが、 まれに UN Ⅸの cc などは ANSI 規格に準拠していない場合があります。

3. C言語によるプログラミング 基礎編 第2版

言と引数ー 5.2 関数宣 引数の個数と型の一致 関数の呼び出しにおける実引数と関数のプロトタイプ宣言における仮引数は、その個数と対応す る型が一致しなければなりません。ただし、対応する型が一致していなくても、実引数の型を仮引 数に変換できる場合、関数に引数が渡される前に自動的に型変換されます。 たとえば、以下の関数宣言の場合、その呼び出し側は、必す 4 個の引数で、かっ、その引数の型 は整数型、整数型、実数型、整数型の順になっていなければいけません。 ex4 ( int x ′ int y ′ double 2 ′ int k ) ー double 具体的な関数呼び出しの例で示すと、 リスト 5.12 のようになります。 リスト 5.12 関数の引数の個数と型の一致 int main ( VOid ) int C : double / ☆ここでプロトタイプ宣言してもよい☆ / double ′ int ) ー ex4 ( 土 n セ′ int, double O O 0 セ 3 5 ,Q 2 ..Q return 0 : int c ) double ex4 ( int a, 土 n セ b, double t ー return a 十 b 十セ十 c; 3 番目の呼び出しの例のように、仮引数が実数型ならば、実引数には整数型の定数を記述しても 自動的に 5.0 に型変換されます。 なお、リスト 5.12 では、 main 関数の局所変数定義のところで関数 ex4 のプロトタイプ宣言をして いますが、プロトタイプ宣言はこのように局所変数と一緒に宣言できます。また、次のように他の 変数の定義と混在させて宣言することもできます。 double, int ) ー ex4 ( 土 n セ′土 n セ′ double t ′ この関数 ex3 を実行しても、何も起こらないのではないかと思う人もいるかもしれません。しかし、関数 ex3 内で printf 文によって計算結果を出力したり、 10 章で学習するファイル人出力を行うことで意味のある関数となります。 マ 22

4. C言語によるプログラミング 基礎編 第2版

5 早 関 数 の終わりまで有効で、関数 ( 最大のプロック ) の外側での宣言は宣言の直後から、 位の終わりまで有効です。 外部変数の通用範囲をプログラムの形式で示します。 く < プログラムの形式 > > 5.12 void p て 0C3 ( void extern a ー / ☆ここから別ファイル☆ / void p て 0C2 ( void void p て 0C1 ( void int b; 土 n セ a; ← 202 外部変数の通用範囲 そのコンパイル単 ファイル A ファイル B 工ラー 外部変数 a の通用範囲はここから。 外部変数 b の通用範囲はここから。 外部変数 a 、 b の通用範囲は このファイルが終わるまで。 外部変数 a の extern 宣言 外部変数 a の extern 宣言の 通用範囲はこのファイルが 終わるまで。 変数 b は、このファイルからは 参照できない。

5. C言語によるプログラミング 基礎編 第2版

9.5 ユーザ定義型 typedef struct て 011 name [ 32 char birth; int int ZIP; 82 address [ char tel[ 20 ]; char } て 011 ー t ー / ☆名前 / ☆生年月日☆ / / ☆郵便番号☆ / / ☆住所☆ / / ☆電話番号☆ / し 構造体宣言と typedef 宣言を同時に行うのが常套手段となっています。 このように r01 い型を使うと、変数やポインタを簡潔に定義することができます。 て 011 ーセ my_data : て 011 ーセ *p, 第 3 の利点は、移植性 , 30 を高めることです。たとえば、 int 型を 2 バイトと想定したプログラムが あるとしましよう。このプログラムを int 型が 4 バイト、 short 型が 2 バイトのマシンに移植したい とき、 int 型を short 型に置き換えなければなりません。このような場合、 int 型を直接使用せずに typedef 宣言して別名を使用しておけばよいのです。 pedef 宣言の修正だけで移植ができるように なり、プログラムのいろいろな箇所を修正する必要がなくなりますマ 31 0 -coffee-break 9.6 typedef が有効な局面 ( 2 ) # define より typedef が優れている例をもう 1 つ紹介しましよう。 たとえば struct { int int という構造体タグを省略した構造体があるとして、構造体の代入を考えてみましよう。 #define XY struct{ int x; int y; } XY coordinatel ′ coordinate2 : XY coordinate3 ー / ☆正しい代入☆ / / ☆これは誤り☆ / coordinate2 ー coordinate3 : coordinatel coordinatel なぜ 2 番目の代入が誤りなのでしよう。 #define はプリプロセッサにより置換されるため、構造体宣言がそのまま XY の場所に展開されるこ とになります。つまり、構造体タグを省略した構造体宣言を 2 回 ()Y の数 ) 行うことになります。さ らに、構造体タグを省略した場合は、コンパイラが重複しない不明な名前を与えることになっていま 319

6. C言語によるプログラミング 基礎編 第2版

9.5 ユーザ定義型ー - typedef 構造体は複数のデータ型を組み合わせて新たな型を作り出すものでしたが、 typedef は既存の データ型に別名を付ける機能をもっています。別名ですから実質的に新たな型を作り出すわけでは 9.5.1 それでは typedef を用いて、論理値を格納する boolean 型 , 27 を作成してみましよう。 に、 typedef とは型名 (type name) を定義 (define) するという意味です。 ありませんが、 typedef 宣言された型は独立した新しい型として利用することができます。ちなみ こでは、 int 型をベースに宣言します。 #define #define typede f boolean if( 条件 FALSE TRUE int 0 1 result; boolean; / ☆偽☆ / / ☆真☆ / result else{ result TRUE ー FALSE; typedef とは直接関係ありませんが、 boolean 型変数に格納する値として、 FALSE と TRUE を # de ⅱ ne で定義しています。これらの値は、 boolean 型が int 型をベースにすることを考慮して、数 値の 0 と 1 にしています。 typedef 宣言は、次のような構文形式をもちます , 28 typedef すでに宣言されている型名新しく付ける型名 新しく宣言された型は、べースにした型の性質を引き継ぎます。つまり、 boolean 型は int 型と まったく同様に変数定義や型変換ができるのです , 29 。上の例では pedef 宣言の後、 bo 。 lean 型の変 数 result を定義して、その後のプログラムで利用しています。 typedef において注意しなければならないのは、宣言された型名はあくまでも別名であり、メモ リ上の大きさや演算の規則などは元の型と同じであるということです。別名を付けることは # de ⅱ ne でもできますが、いろいろな場面を考慮すると pedef の方が有利な点が多いようです。 また、 pedef で作る型名には、次のように一 t を付けることが慣習になっています。 typedef int boolean t; マ 28 マ 29 マ 27 001ea は数学におけるプール代数 ( bo 司 ean algebra ) に由来するものです。コンビュータ用語としては真 ( true ) か偽 ( 同 se ) かの論理値を示すものとして用いられます。 c では論理値専用の型は用意されていませんが、 Java などはじめか ら論理値型が組み込まれている言語も存在します。 正式には typedef はもう少し複雑な構文をもちますが、これについては応用編で説明します。 int がなくなって boolean になったのではありません。 int は int として通常どおり使用できます。 317

7. C言語によるプログラミング 基礎編 第2版

5 章関数 しかし、 全体構造を、次項以降で詳しく説明しましよう。 これは一般的なプログラム構造ではありませんマ 9 。関数を用いた一般的なプログラムの 関数を含むプログラムの構造 図 5.4 に関数を用いた一般的なプログラム形式を示します。 ロプログラムの一般形式 #include くへッダファイル名 > プロトタイプ宣言 int main ( void ) 言部および定義 メインのプログラム return 0 ー 関数型関数名 ( 仮引数 ) 言部および定義 関数のプログラム return 結果の値 ・図 5.4 プログラムー般形式 メインプログラム 関数プログラム 今までプログラムと呼んでいた部分は、関数のプログラムと区別するため、メインプログラム (mainprogram) と呼びます。もちろん、プログラムの実行は、メインプログラムの最初の文から 開始されます。関数のプログラムは、その関数が呼び出されてはじめて実行されます。もし、メイ ンプログラムの中で関数プログラムの呼び出しが一度も行われないと、その関数のプログラムは ソースプログラムに記述されていても一度も実行されません。 プロトタイプ宣言ⅵ 0 とは、そのプログラム内で使用する関数の名前や引数の順序と型を指定す るために設けられた文法規則です。 C コンパイラは、上から下へ一度だけ、プログラムを読み込ん でコンパイルします。プロトタイプ宣言がないと、コンパイラは引数の情報が不明で int 型を返す 関数とみなしてとりあえずコンパイルします。しかし、この仮定は多くの場合うまくいきません。 そのため、プロトタイプ宣言がないと、関数呼び出しのコンパイルができないと考えた方がよいで しよう。リスト 5.3 においては関数定義が先にあるので、プロトタイプ宣言は不要となります。 今までプログラムの最初に、おまじないとして もちろん、このプログラムをコンパイルすれば問題なく動作します。 JIS の用語では、関数原型といいます。 マ 10 166

8. C言語によるプログラミング 基礎編 第2版

9 章構造体とユーザ定義型 共用体 (union) 共用体 ( union ) は、宣言やメンバの参照方法など構文の面では構造体と似ています。 用体のメンバはメモリ上の領域を、その名のとおり共用する点で構造体と異なります。 それでは実際の共用体宣言と共用体変数の定義を見てみましよう。 しかし、 union name_or_age { char [ 32 ] name; / ☆名前☆ / / ☆年齢☆ / int } ViSitor,• age : 最初の union が共用体宣言のキーワードです。次の name ー or ー age が共用体タグで、 この共用体の 名前です。中括弧 { } に囲まれた部分に共用体のメンバを記述します。この例では、 2 つのメンバ、 name と age が宣言されています。最後のⅵ sitor はこの共用体の変数です。このように、共用体宕 言は構造体の宣言によく似ています。しかし、メモリ上でのふるまいは構造体と大きく違います。 この共用体変数ⅵ sit 。 r のメモリ上のイメージを図 9.6 に示します。 0 age 4 8 20 name 24 28 32 ( バイト ) ・図 9.6 共用体メンバの配置イメージ それでは、実際に共用体を使ってみましよう。 バが 1 つだけに限られることになります。 ように重なり合った形で情報を格納することはできませんから、共用体では同時に使用できるメン name が共用体変数の最初の 4 バイトを共用している様子が示されています。実際のメモリはこの メンバは共用体の先頭から重なり合って定義されているのです。図 9.6 では、 2 つのメンバ age と 共用体における各メンバの先頭アドレスは、すべて同じアドレスになります。つまり、すべての uni 0 れ name_or__age { int main ( VOid ) #include く stdio . h> リスト 9.2 共用体の利用 char 土 n セ } ViSitor; int input— 304 name[ 32 ]; age : name ー / ☆名前 / ☆年齢 / * 名前を入力するかどうか☆ /

9. C言語によるプログラミング 基礎編 第2版

9 章構造体とユーザ定義型 ここで、 struct は構造体宣言を示すキーワードです。次の ro Ⅱは、この構造体に付ける名前で構 造体タグ ( tag ) と呼ばれます。構造体タグは省略することもできます , 5 。中括弧 { } に囲まれた中は、 構造体のメンバ ( member ) と呼ばれ、メンバどうしの名前が重複しなければ、どのような名前 ( 変 ここでは変数を定義しているわけではないことに注意し 数名 ) でも書くことができます。ただし、 てください。実際の変数を定義するためには、次のように構造体タグを使った変数定義が必要です。 struct て 011 my—data; 上記の変数定義によって、 r 。Ⅱ型の構造体変数 my ー data を利用することが可能になります , 6 ・ } ; のことを構造体テンプレートと呼ぶことがあります。テンプレート 構造体宣言 struct roll{ は枠型、雛型とも訳されますが、こでは構造体変数を作り出すための型と考えればよいでしよう。 実世界の名簿に例えるなら、名簿の枠線を引いて「名前」や「住所」など各項目の名前だけを記し た台紙が構造体テンプレート、そして台紙を新しい紙にコビーして誰かの情報を書き込んだものが 構造体変数に相当します。 《台紙 : テンプレート》 住所 郵便番号 名、前 生年月日 電話番号 《名簿 : 変数》 郵便番号 住所 台紙をコピーして名簿を作る 生年月日 電話番号 ・図 9.3 構造体テンプレートのイメージ roll タグを使って、 3 人分の構造体変数を定義するには、以下のようにします。このそれぞれの を繰り返し行うことによって、同じ構造をもつ構造体変数を複数定義することができます。 台紙を繰り返しコビーして新しい名簿のページをどんどん作り出せるように、構造体変数の定義 変数の中に、 ro Ⅱタグのメンバを格納するデータ領域が確保されます。 my—data; her data ー his data; このようにすることで、実際の名簿のように多数の人間の情報をまとめて管理することが容易に struct struct struct て 011 て 011 て 011 なります。構造体が真の力を発揮するのは、まさにこのような場面なのですが、実際の例について は 9.4 節まで待ってください。その前に、構造体の基本的な使い方をマスターしておきましよう。 0 構造体宣言と変数の定義を同時に行う 構造体宣言と構造体変数の定義は同時に行うことが可能です。 マ 5 296 省略については本項で後述します。 9.5.3 項に宣言と定義の違いについて解説しています。

10. C言語によるプログラミング 基礎編 第2版

5 章 関数 ソースファイル : XXXXXX . c ヘッダファイル : XXXXXX . h のように、拡張子を . c マ 13 と . h とするようにしています。 このことから、 powint 関数を一般的なプログラム構造として記述するとリスト 5.4 のようになり ます。なお、このプログラムでは、 powint 関数の戻り値を直接 printf 関数の実引数として使用する 己述になっている点に注意してください。 リスト 5.4 整数の正のへき乗を計算する関数 ( その 4 ) #include く stdio . h> 二二ロ ← p 。 w 土 nt 関数のプロトタイプ宣 int powint ( int x, 土 n セ y ) ・ int main ( VOid ) 土 n セ土 : 0 ー i く = 10 : i 十十 ) fo て ( i i ′ powint ( 2 ′ i) レ printf ( "%dYt%dYn" return 0 : ←関数の定義 土 n セ powint ( int x, int p ) int y = 1 ー while ( p— return y ー リスト 5.3 と違う点は、 main 関数で powint 関数を使用するため p 。 wint 関数の呼び出しを行う前に powint 関数のプロトタイプ宣言を行っている点です。プロトタイプ宣言は、一般に以下のようにし ます。 くくプログラムの形式 > > 5.2 関数のプロトタイプ宣言 ′引数名 n の型名引数名 n ) 関数の型名関数名 ( 引数名 1 の型名引数名 1 ′ この宣言により関数の型、関数への引数の型などを明確にし、コンパイルでのエラー検出率を大 幅に向上しています。たとえば、リスト 5.4 の main 関数で使用している int 型の i を V13 処理系によっては、 . cpp や℃の場合もあります ( C + + の処理系の場合 ) 。 168