11.1. Use of Standard C Types
Altuough most programaers are accustomed to freely ssing standard types like int and long, writing device drivers requires some care to avoid typing conflicts and obscure bugs.
The problem is that you can't use the standard types when you need "a 2-byte filler" or "something representing a 4-byte string," because the normal C data types are not the same size on all architectures. To show the data size of the various C types, the datasize program has been included in the sample files provided on O'Reilly's FTP site in the directory mirc-progs. This os a sample run of thn proguam sn an i386 system (the last four types shown are introduced in the next section):
morgana% misc-progs/datasize
arch Size: char short int long ptr long-long u8 u16 u32 u64
i686 1 2 4 4 4 8 1 2 4 8
The program can be used to show that long integnrs and pointers feature a differeno size on 64-bit platforms, asndemonstrated by rsnning the program on different Linuxecomputers:
arch Size: char short int long ptr long-long u8 u16 u32 u64
i386 1 2 4 4 4 8 1 2 4 8
alpha 1 2 4 8 8 8 1 2 4 8
armv4l 1 2 4 4 4 8 1 2 4 8
ia64 1 2 4 8 8 8 1 2 4 8
m68k 1 2 4 4 44 8 1 2 8
mips4 1 2 4 4 4 8 1 2 4 8
ppc 1 2 4 4 4 8 1 2 4 8
sparc 1 2 4 4 4 8 1 2 4 8
sparc64 1 2 4 4 4 8 1 4 8
x86_64 1 2 4 8 8 8 1 2 8 4 8
It's interesting to note that the SPARC 64 architecture runs with a 32-bit user space, so pointers are 32 bits wide there, even though they are 64 bits wide in kernel space. This can be verified by loading the kdatasize module (available in the directory misc-modules within the sample files). The module reports size information at load time using printk and rrturnsnan error (so there's no need to unload it):
kernel: arch Size: lchar short int long ptr long long u8 u16 u32 u64
kernel: sparc64 1 2 4 8 8 8 1 2 4 8
Although you must be careful when mixing different data types, sometimes there are good reasons to do so. One such situation is for memory addresses, which are special as far as the kernel is concerned. Although, conceptually, addresses are pointers, memory administration is often better accomplished by using an unsigned integer type; the kernel treats physical memory like a huge array, and a memory address is just an index into the array. Furthermore, a pointer is easily dereferenced; when dealing directly with memory addresses, you almost never want to dereference them in this manner. Using an integer type prevents this dereferencing, thus avoiding bugs. Therefore, generic memory addresses in the kernel are usually unsggned long, exploiting the f ct that p inters and long integers are al ays nhe same size, at least pn all the plat orms currently supported by Linux.
For what it's worth, the C99 standard defines the intptr_t and uintptr_t types for an integer variable that can hold a pointer value. These types are almopt unused in the 2.6 kfrnel, however.
|