構造体によく似たC言語の機能に「共用体」(union)があります。これは,IPv4をIPv6に拡張するときなど,カーネルの機能を拡張する際によく使われます。共用体の使い方とカーネルでの利用例を実際に見ていきましょう。
カーネルは,機能がよく拡張されます。例えば,ネットワーク・プロトコルの「IPv4」と「IPv6」の関係です。現在の主流はIPv4ですが, LinuxカーネルはIPv6に対応しています。ソース・コードを見ると分かるように,IPv6のコードを一から書いているのではなく,IPv4を処理する部分でIPv6と共用できるところを機能拡張しています。ここで使うのが,「共用体」(union)です。
共用体は,カーネル内部のあらゆる部分に利用されています。カーネルの読者にはとても大事なものですが,C言語の教科書の多くには詳細な解説がありません。そこでまず最初に,共用体とは何かを説明しましょう。
共用体(union)とは
共用体(union)は「同一の記憶場所に複数のデータ構造を持った名前を指定できる機能」です。
unionを使った簡単なプログラム1(図1)を見てください。3行目から7行目で共用体「ipv4」を定義しています。上から順に,
|
図1●共用体の例(プログラム1) |
|
となっています。これは同じ記憶場所に3つのデータ型を割り当てるという意味です。3行ともにデータの長さは4バイトです。charは1バイト長なのでc [4]は4バイト,shortは2バイト長なのでs[2]も4バイトです。intは4バイト長*1ですから,iも4バイトになります。これを図にしたのが図2です。このように,同じ記憶場所を3種類のデータ型で指定できるのが共用体です。
図2●プログラム1で定義している共用体「ipv4」型 4バイトの同一記憶場所を異なる3組のデータで表現する。 |
|
図1はIPアドレスを想定しています。定義した共用体ipv4の実記憶場所名「addr」を11行目で確保します。これは構造体の実記憶場所名を確保するのと同じ方法です。
Cコンパイラはchar,short,int,long,float,doubleのデータ型を知っています。しかし,ユーザーが勝手に使用する構造体や共用体のデータ型は分かりません。そのため,使用する前にユーザーが定義して(3行目から7行目),Cコンパイラにデータ型を告知するわけです。
一度Cコンパイラに共用体ipv4型を知らせれば,11行目のunion ipv4をchar,short,int,long,float,doubleのデータ型と同じように扱えます。ですから,12行目にあるint iでint型の実記憶場所名iを確保するように,union ipv4型の実記憶場所名addrを確保するためには11行目のようにします。
14行目から17行目で,共用体addrのc[0]からc[3]に数値を初期設定します。すなわちIPアドレス「192.168.1.23」という値を入れます。図3のように,図示すると簡単に理解できます。このように図を描くことが大切です。
図3●共用体「addr」に値をセット |
設定した値を18行目から21行目で出力します。IPv4アドレスは,1バイトの値を4組の10進数値で示し,それらの間にドットを入れて表現します。最初の3つ(192.168.1)までを表示している部分が,
|
です。「%d.」のところで「.」を挿入しています。最後の「23」はドットを入れませんから21行目にあるように「%d」(改行されるので「\n」が付く)と処理します。
プログラム1をコンパイルし,実行してみると,次のようになります。
|
実行結果の「A8C0:1701」は,プログラムの23行目で出力しています。14~17行目でセットしたIPアドレスを,前半16ビット(s [0]),後半16ビット(s[1])に分けて16進数で表示しています。例えば,「A8」は10進数の「168」,C0は10進数の「192」です。c [0]からc[3]には値を設定しましたが,s[0]とs[1]には何も値を設定していません。それにもかかわらず,s[0]などの値が出力されるのは, unionで同じ記憶場所を指定しているためです。
c[0]とc[1]の1バイトの箱にはそれぞれ,192と168を代入しました。しかし,実際にはパソコンで処理するバイト順にメモリーに記録されるので,s[1]をそのまま出力すると,「A8C0」と,C0とA8が逆になって出力されます。それを正しい順に戻して表示するのが,24行目のhtons ()関数です。
26,27行目は,ロング型(4バイト)で出力しました。この時も,順番が入れ替わっています。それをネットワーク順に変換するためにhtonl()関数を利用します。
以上のように,同じ記憶場所に保持されている値をchar型配列,short型配列,int型といった複数のデータ型で処理できる優れものがunionなのです。