Most commonly used data types in the kernel have their own
typedef
statement, thus preventing any portability problems. For
example, a process identifier (pid) is usually pid_t
instead of
int
. Using pid_t
masks any possible difference in the
actual data typing. I use the expression ``interface-specific'' to
refer to the programming interface to specific data items.
Other data items that belong to a specific ``standard'' type can be
considered interface-specific as well. A jiffy count, for instance, is
always unsigned long
, independent of its actual size--would
you like using jiffy_t
every so often?
I’m concentrating here on the first class of interface-specific
types, the ones ending in _t
.
The complete list of _t
types appears in
<linux/types.h>
, but the list is rarely useful. When you need
a specific type, you’ll find it in the prototype of the functions
you need to call or in the data structures you use.
Whenever your driver uses functions that require such ``custom'' types and you don’t follow the convention, the compiler issues a warning; if you use the -Wall compiler flag and are careful to remove all the warnings, you can feel confident that your code is portable.
The main problem with _t
data items is that when
you need to print them, it’s not always easy to choose the right
printk or printf format, and warnings you
resolve on one architecture reappear on another. For example, how
would you print a size_t
which is unsigned long
on some platforms and unsigned int
on some other?
Whenever you need to print some interface-specific data, the best
way to do it is by casting the value to the biggest possible type
(usually long
or unsigned long
), and then printing it
through the corresponding format. This kind of tweaking won’t
generate errors or warnings because the format matches the type, and
you won’t lose data bits because the cast is either a null operation or
an extension of the item to a bigger data type.
In practice, the data items we’re talking about aren’t usually meant to be printed, so the issue applies only to debugging messages. Most often, the code needs only to store and compare the interface-specific types, in addition to passing them as arguments to library or kernel functions.
Although _t
types are the correct solution for most
situations, sometimes the right type doesn’t exist. This happens
for some old interfaces, which haven’t yet been cleaned up.
The one ambiguous point I’ve found in the kernel headers is
data typing for I/O functions, which is loosely defined (see the
section Section 8.1.1 in Chapter 8). The loose
typing is mainly there for historical reasons, but it can create
problems when writing code. Personally, I often get into trouble by
swapping the arguments to out functions; if
port_t
were defined, the compiler would pinpoint these
errors.
18.118.186.143