共用体と列挙型
構造体のビットフィールドの説明の次として、共用体・列挙型・typedefなどの説明を行う。
共用体
共用体は、複数のデータの中でどれか1つを保存するような処理で使われる。 基本的に構造体の宣言とほぼ同じだけれど、 各要素のメモリ領域を個別に確保するのが構造体。 共用体は各要素の領域は1つで記憶領域が共用される。
union Data { char string[ 10 ] ; int number ; double real ; } ; union Data x ; strcpy( x.string , "hoge" ) ; x.number = 123 ; x.real = 2.3456 ; // 記憶場所は1つだけ
今回は実用っぽいネタということで、以下の処理を示す。 共用体だけでは、中身が解らないので一緒にデータを区別する情報を保存することで、 配列に違うデータを保存する方法。
struct Data { int type ; union { // さりげなく無名共用体... char string[ 10 ] ; int number ; double real ; } ; } ; void setString( struct Data* p , char s[] ) { p->type = 1 ; strcpy( p->string , s ) ; } ; void setInteger( struct Data* p , int x ) { p->type = 2 ; p->number = x ; } ; void setReal( struct Data* p , double x ) { p->type = 2 ; p->real = x ; } ; void print( struct Data* p ) { switch( p->type ) { case 1 : printf( "%s" , p->string ) ; break ; case 2 : printf( "%d" , p->number ) ; break ; case 3 : printf( "%f" , p->real ) ; break ; } } void main() { struct Data table[ 3 ] ; setString( &table[ 0 ] , "abc" ) ; setInteger( &table[ 1 ] , 1234 ) ; setReal( &table[ 2 ] , 23.45 ) ; for( int i = 0 ; i < 3 ; i++ ) print( &table[ i ] ) ; }
列挙型
プログラムで、例えば1週間の情報の日月火という曜日を扱う場合、 以下のような記述となることも多い。
#define SUN 0 #define MON 1 : #define SAT 6 int week ; for(...) { if ( week == MON ) { //月曜日の処理... } }
この時、#defineの羅列で数字を規則的に連番を振るのは面倒となる。 これをやってくれるのが列挙型。
enum WEEK { SUN , MON , TUE , ... , SAT } ; enum WEEK week ; for( ... ) { if ( week == MON ) { // 月曜日の処理... } }
列挙型変数には、列挙型の要素名の定数以外は代入できないし、 コンパイラによってはswitch文で対応要素の処理が未記載だったら 警告してくれるなど、間違った記載をできないようなチェックが便利。
typedef…
typedefは、自分で定義した型に新しい名前をつける機能。 通常は以下のように使う。
typedef unsigned int uint_t ; uint_t x ; // xは符号なしint型となる。 typedef struct DATA { char name[ 10 ] ; int age ; } Data ; Data saitoh ; strcpy( saitoh.name , "saitoh" ) ; saitoh.age = 47 ; typedef enum WEEK { SUN , MON , ... SAT } Week ; Week wday ; wday = MON ;
OSの基本と資源管理
先週で説明の終えていなかった、機械語の生成の話の説明の後、OSについての具体的な説明を行う。
機械語の生成
先週末にコンパイラ方式とインタプリタ方式の話の次段階として、 機械語などはCPUやOSに依存する補足をして、 Javaにおける仮想マシンを用いたバイトコードインタプリタなどの説明を行う。
プログラムの機械語の実行の説明として、コンパイラによる中間コードの生成や、 リンカによる中間コードとライブラリの結合の話を行う。 また、リンクにも静的リンクと動的リンクがあり、 通常はプログラムの中にライブラリが埋め込まれる静的リンクがとられる。 しかしマルチタスクでは、メモリ中にライブラリの機械語が複数でてくると、 メモリのムダになるので、OSにライブラリを展開してもらう動的リンク方式があることを説明。動的リンクを使えば、ライブラリの修正アップデートも簡単といった利点を説明。
OSとは、
OSとは、基本ソフトウェアとよばれ、 (a)制御プログラム(狭義のOS,カーネル)と、(b)開発環境(言語プロセッサ等)、(c)ユーティリティ(CUI/GUI等)から成ることを説明する。
OSの機能として、周辺装置とのデータのやり取り・制御方法を共通化することで、 プログラム作成の労力削減が可能となる。 もう一つの重要な機能は、不用意なことをできなくすることによるデータの保護であり、 ハードを壊すような制御などを実行させない。 他のプロセスの動きを阻害するようなメモリアクセスをさせない。 他人のファイルを権限もないのに読めるようなことをさせない。…といった保護が重要。
これらの共通化や保護の対象となるものを資源(resource)と呼ぶ。 たとえば、キーボードやハードディスクといった周辺機器(物理的なリソース)、 計算に必要となる主記憶(メモリ)、CPUを利用する時間(抽象的なリソース)などがある。
プログラムの動く単位として、利用者視点でトータルの1つのサービスを提供する処理は、 ジョブと呼ばれる。これに対し、CPUが他の処理から保護する仕事の単位はプロセスと呼ばれ、ジョブは複数のプロセスで実現される場合もある。 一方、並行処理では複数のプロセスで実行するのが普通だが、共通のメモリ情報を使いながら動く処理は記述が面倒となる。 これに対しスレッドは、並列する複数の処理で同一メモリを利用できるものを指す。 複数のスレッドで1つのプロセスを構成する。