#language jp

''このページはWritingPortableDriversセクションの一部です。''<<BR>>

== カーネル内で使用されるデータ型 ==
原文: [[http://kernelnewbies.org/InternalKernelDataTypes|InternalKernelDataTypes]]

移植性の高いコードを書くときに覚えておきたいもっとも基本的なルールは、
変数の大きさをどのくらいにする必要があるかに気を付けるというものです。
データ型{{{int}}}と{{{long}}}の変数のサイズは、プロセッサごとに異なります。
さらに変数には、符号付き、符号なしといった違いもあります。このため、変数の
サイズを一定のビット数にする必要があり、符号付きか符号なしのどちらかに
しなければならない場合、組み込みのデータ型を使用する必要があります。
次に示すtypedefされたデータ型はヘッダファイルlinux/types.hで定義されていて、
カーネルコードのどこででも使用することができます。

{{{
 u8    unsigned byte (8 bits)
 u16   unsigned word (16 bits)
 u32   unsigned 32-bit value
 u64   unsigned 64-bit value
 
 s8    signed byte (8 bits)
 s16   signed word (16 bits)
 s32   signed 32-bit value
 s64   signed 64-bit value
}}}

たとえば、i2cドライバサブシステムには次のような関数があり、i2cバス上の
データ送受信に使用されています。

{{{
#!cplusplus
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value);
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value);
}}}

これらの関数はすべて符号付き32ビット値を返し、パラメータのvalueとcommandは
どちらも符号なし8ビット値を取ります。このコードはこれらのデータ型を使用して
いるおかげで、どのような種類のプロセッサへも移植することができます。

ユーザ空間のプログラムで参照される可能性のあるコードの中で変数を使用する
場合は、次のような外部から利用可能なデータ型を使用する必要があります。
このデータ型の使用例は、ioctl()呼び出しを介して受け渡されるデータ構造に
見られます。これらのデータ型もヘッダファイルlinux/types.hで定義されています。

{{{
__u8   unsigned byte (8 bits)
__u16   unsigned word (16 bits)
__u32   unsigned 32-bit value
__u64   unsigned 64-bit value
 
__s8    signed byte (8 bits)
__s16   signed word (16 bits)
__s32   signed 32-bit value
__s64   signed 64-bit value
}}}
'''FIXME {{{__le16}}}とその仲間たちを追加すること'''<<BR>>

たとえば、ヘッダファイルusbdevice_fs.hには、ユーザ空間のプログラムがUSBデバイス
と直接話すときに使用される、さまざまな構造体が定義されています。次に示すのは
デバイスにUSBコントロールメッセージを送信するために使用されるioctlの定義です。

{{{
#!cplusplus
struct usbdevfs_ctrltransfer {
        __u8 requesttype;
        __u8 request;
        __u16 value;
        __u16 index;
        __u16 length;
        __u32 timeout;  /* in milliseconds */
        void *data;
};
#define USBDEVFS_CONTROL_IOWR('U', 0, struct usbdevfs_ctrltransfer)
}}}

64ビットマシンがさらに普及してきたことで、ポインタのサイズが符号なし整数の
サイズと同じではないために数多くの問題が発生しました。ポインタのサイズは
unsigned longのサイズと等しくなります。これはget_zeroed_page()のプロトタイプ
宣言に見ることができます。

{{{
extern unsigned long FASTCALL (get_zeroed_page(unsigned int gfp_mask))
}}}

{{{get_zeroed_page()}}}はゼロで初期化された割り当て可能なメモリページを
返します。この関数はunsigned longを返し、その値はおそらく特定のデータ型に
キャストされるはずです。その方法は、次に示す{{{drivers/char/serial.c}}}で
定義されている{{{rs_open()}}}関数のコードの断片に見ることができます。

<<BR>>'''FIXME この例は2.4の頃の古い例である。'''

{{{
#!cplusplus
static unsigned char *tmp_buf;
unsigned long page;
 
if (!tmp_buf) {
        page = get_zeroed_page(GFP_KERNEL);
        if (!page)
                return -ENOMEM;
        if (tmp_buf)
                free_page(page);
        else
                tmp_buf = (unsigned char *)page;
}
}}}

unsigned longの代わりに使用すべきネイティブなカーネルデータ型がいくつかあります。
以下に示すのはその一部です。

{{{pid_t}}}, 
{{{key_t}}}, 
{{{gid_t}}}, 
{{{size_t}}}, 
{{{ssize_t}}}, 
{{{ptrdiff_t}}}, 
{{{time_t}}}, 
{{{clock_t}}}, and {{{caddr_t}}}.

あなたのコードの中でこれらの型のどれかを使用する必要があるときは、そのデータ
型を使用してください。そうすることで多くの問題を避けることができるでしょう。