📄 (ldd) ch10-合理使用数据类型(转载).htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0030)http://joyfire.net/lsdp/13.htm -->
<HTML><HEAD><TITLE>(LDD) Ch10-合理使用数据类型(转载)</TITLE>
<META http-equiv=Content-Type content="text/html; charset=GB2312">
<META content="MSHTML 6.00.2600.0" name=GENERATOR></HEAD>
<BODY text=#ffffff>
<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>
<TBODY>
<TR>
<TD colSpan=3 height=2>
<TABLE cellSpacing=0 cellPadding=0 width="100%" bgColor=#666666
border=0><TBODY>
<TR>
<TD width="38%" height=4>
<DIV align=center><A href="http://joyfire.net/index.html"><FONT
color=#ffffff>index.html</FONT></A></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="http://joyfire.net/jln/index.htm"><FONT
color=#ffffff>笔记</FONT></A></DIV></TD>
<TD width="1%" height=4>
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A
href="http://joyfire.net/kernelscr/index.html"><FONT
color=#ffffff>源码</FONT></A></DIV></TD>
<TD width="1%" height=4>
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="http://joyfire.net/document.htm"><FONT
color=#ffffff>文档</FONT></A></DIV></TD>
<TD width="1%" height=4>
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="http://joyfire.net/download.htm"><FONT
color=#ffffff>下载</FONT></A></DIV></TD>
<TD width="1%" height=4>
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="http://joyfire.net/links.htm"><FONT
color=#ffffff>链接</FONT></A></DIV></TD>
<TD width="1%" height=4>
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="http://joyfire.net/about.htm"><FONT
color=#ffffff>关于</FONT></A></DIV></TD>
<TD width="1%" height=4>
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="mailto:joyfire@sina.com"><FONT
color=#ffffff>联系</FONT></A></DIV></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE borderColor=#666666 cellPadding=2 width="90%" align=center border=2>
<TBODY>
<TR>
<TD bgColor=#000000>
<P align=center><A href="http://joyfire.net/lsdp/index.htm"><FONT
color=#ffffff size=2>目录页</FONT></A> | <A
href="http://joyfire.net/lsdp/12.htm"><FONT color=#ffffff
size=2>上一页</FONT></A> | <A href="http://joyfire.net/lsdp/14.htm"><FONT
color=#ffffff size=2>下一页</FONT></A></P>
<P align=center><FONT face=黑体 color=#ffffff size=6>(LDD) Ch10-合理使用数据类型(转载)
</FONT></P><SPAN style="LINE-HEIGHT: 1; LETTER-SPACING: 0pt"><FONT
color=#ffffff size=3>
<P>发信人: Altmayer (alt), 信区: GNULinux<BR>标 题: (LDD) Ch10-合理使用数据类型(转载)<BR>发信站: 饮水思源 (2001年12月13日08:57:31 星期四), 站内信件<BR> <BR>【 以下文字转载自 <FONT
color=#00ff00>UNIXpost </FONT>讨论区 】<BR>【 原文由<FONT
color=#00ff00> altmayer.bbs@bbs.nju.edu.cn,</FONT> 所发表 】<BR> <BR>【 以下文字转载自 <FONT
color=#00ff00>altmayer </FONT>的信箱 】<BR> <BR>第10章 合理使用数据类型<BR> <BR> <BR> 在进一步讨论更深的主题之前,我们需要先停一停,快速地回顾一下可移植问题。L<BR>inux1.2版本和2.0版本之间的不同就在于额外的多平台能力;结果是,大多数源代码级<BR>的移植问题已经被排除了。这意味着一个规范的Linux驱动程序也应该是多平台的。<BR> <BR> <BR> <BR> 但是,与内核代码相关的一个核心问题是,能够同时存取各种长度已知的数据项(例<BR>如,文件系统数据类型或者设备卡上的寄存器)和利用不同处理器的能力(32位和64位的体<BR>系结构,也有可能是16位的)。<BR> <BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR> <BR>当把x86的代码移植到新的体系结构上时,核心开发者遇到的好几个问题都和不正确的数<BR>据类型相关。坚持强数据类型以及编译时使用-Wall -Wstrict-prototypes选项能够防止<BR>大部分的臭虫。<BR> <BR> <BR> <BR>内核使用的数据类型划分为三种主要类型:象int这样的标准C语言类型,象u32这样的确<BR>定数据大小的类型和象pid_t这样的接口特定类型。我们将看一下这三种类型在何时使用<BR>和如何使用。本章的最后一节将讨论把驱动器代码从x86移植到其它平台上可能碰到的其<BR>它一些典型问题。<BR> <BR> <BR> <BR>如果你遵循我提供的这些准则,你的驱动程序甚至可能在那些你未能进行测试的平台上<BR>编译并运行。<BR> <BR>使用标准C类型<BR>大部分程序员习惯于自由的使用诸如int和long这样的标准类型,而编写设备驱动程序就<BR>必须细心地避免类型冲突和潜在的臭虫。<BR> <BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR> <BR>问题是,当你需要“2个字节填充单位(filler)”或“表示4个字节字符串的某个东西”<BR>时,你不能使用标准类型,因为通常的C数据类型在不同的体系结构上所占空间大小并不<BR>相同。例如,长整数和指针类型在Alpha上和x86上所占空间大小就不一样,下面的屏幕<BR>快照表明了这一点:<BR> <BR> <BR> <BR>morgana% ./datasize<BR> <BR>system/machine: Linux i486<BR> <BR>sizeof(char) = 1<BR> <BR>sizeof(short) = 2<BR> <BR>sizeof(int) = 4<BR> <BR>sizeof(long) = 4<BR> <BR>sizeof(longlong) = 8<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>sizeof(pointer) = 4<BR> <BR> <BR> <BR>wolf% ./datasize<BR> <BR>system/machine: Linux alpha<BR> <BR>sizeof(char) = 1<BR> <BR>sizeof(short) = 2<BR> <BR>sizeof(int) = 4<BR> <BR>sizeof(long) = 8<BR> <BR>sizeof(longlong) = 8<BR> <BR>sizeof(pointer) = 8<BR> <BR> <BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>sandra% ./datasize<BR> <BR>system/machine: Linux sparc<BR> <BR>sizeof(char) = 1<BR> <BR>sizeof(short) = 2<BR> <BR>sizeof(int) = 4<BR> <BR>sizeof(long) = 4<BR> <BR>sizeof(longlong) = 8<BR> <BR>sizeof(pointer) = 4<BR> <BR> <BR> <BR>datasize程序是一个可以从在O'Reilly FTP站点的misc-progs目录下获得的小程序。<BR> <BR> <BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>在混合使用int和long类型时,你必须小心,有时有很好的理由这样做,一种情形就是内<BR>存地址,一涉及到内核,内存地址就变得很特殊。虽然概念上地址是指针,但是通过使<BR>用整数类型,可以更好地实现内存管理;内核把物理内存看做一个巨大的数组,内存地<BR>址就是这个数组的索引。而且,一个指针很容易被取地址(deference),而使用整数表示<BR>内存地址可以防止它们被取地址,这正是人们所希望的(比使用指针更安全)。因而,内<BR>核中的地址属于unsigned long类型,这是利用了指针和长整数类型大小总是相同这一事<BR>实,至少在所有Linux当前支持的平台上是这样的。我们等着看看将来把Linux移植到不<BR>符合这一规则的平台上的时候,会发生些什么。<BR> <BR>分配确定的空间大小给数据项<BR>有时内核代码需要指定大小的数据项,或者用来匹配二进制结构*或者用来在结构中插入<BR>填充字段对齐数据。<BR> <BR> <BR> <BR>为此目的,内核提供如下的数据类型,它们都在头文件<asm/types.h>中声明,这个文件<BR>又被头文件<linux/types.h>所包含:<BR> <BR> <BR> <BR>u8; /* 无符号字节(8位) */<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>u16; /* 无符号字(16 位) */<BR> <BR>u32; /* 无符号32位数值 */<BR> <BR>u64; /* 无符号64位数值 */<BR> <BR> <BR> <BR>这些数据类型只能被内核代码所访问(也即,在包含头文件<linux/types.h>之前必须先<BR>定义__KERNEL__)。相应的有符号类型也是存在的,但一般不用;如果你需要使用它们的<BR>话,只要把名字中的u替换为s就可以了。<BR> <BR> <BR> <BR>如果用户空间的程序需要使用这些类型,可以在这些名字前面添加2个下划线:__u8和其<BR>它类型是独立于__KERNEL__定义的。例如,如果一个驱动程序需要通过ioctl系统调用与<BR>一个运行在用户空间内的程序交换二进制结构的话,头文件必须将结构中的32位字段定<BR>义为__u32。<BR> <BR> <BR> <BR>重要的是要记住这些类型特定于Linux,使用它们就会防碍软件向其他Unix变体的移植。<BR></P></FONT><FONT
color=#ffffff size=3>
<P>重要的是要记住这些类型特定于Linux,使用它们就会防碍软件向其他Unix变体的移植。<BR>但是,有些情况下也需要明确说明数据大小,而标准头文件(在每个Unix系统上都能找到<BR>的)并未声明较合适的数据类型。<BR> <BR> <BR> <BR>你也许注意到,有时内核也使用一般的数据类型,象unsigned int,用于那些大小与体<BR>系结构无关的项。这通常是为了向后兼容。当u32及其相关类型在1.1.67版本引入时开发<BR>者没办法把存在的数据类型改成新类型,因为当结构字段和赋予的值之间类型不匹配时<BR>,编译器会发出警告+。Linus当初可没预料到为自己使用而编写的这个操作系统会发展<BR>成为多平台的;因此,一些旧的结构的数据类型定义上不是很严格。<BR> <BR>接口特定的类型<BR>内核中最常使用的数据类型有它们自己的typedef声明,这样就防止了任何移植上的问题<BR>。例如,进程号(pid)通常使用pid_t,而不是int。使用pid_t屏蔽了任何实际数据类型<BR>之间可能的差别。我使用“接口特定”这种表述来指代特定数据项的编程接口。<BR> <BR> <BR> <BR>属于指定“标准”类型的其它数据项也可以认为是接口特定的。比如,一个jiffy计数总<BR>是属于unsigned long类型的,独立于它的实际大小-你喜欢那么频繁地使用jiffy_t类<BR>型么?这里我关注的是接口特定类型的第一类,那些以_t结尾的类型。<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR> <BR> <BR>_t类型完整的列表在头文件<linux/types.h>中,但是该列表几乎没什么用。当需要一个<BR>特定类型时,你可以在你要调用的函数原型或者使用的数据结构中找到它。<BR> <BR> <BR> <BR>只要你的驱动程序使用了需要这种“定制”类型的函数,又不遵循惯例的时候,编译器<BR>都会发出一个警告;如果你打开-Wall编译开关并且细心地去除了所有警告,你就可以自<BR>信你的代码是可移植的了。<BR> <BR> <BR> <BR>_t数据项的主要问题是当你需要打印它们的时候,并不总是容易选择正确的printk或者p<BR>rintf格式,并且你在一种体系结构上排除了的警告,在另一种体系结构上可能又会出现<BR>。例如,当size_t在一些平台上是unsigned long,而在另外一些平台上却是unsigned<BR>int时,你怎么打印它呢?<BR> <BR> <BR> <BR>任何时候,当你需要打印一些特定接口的数据的时候,最行之有效的方法就是,把它强<BR>制转换成最可能的类型(通常是long或unsigned long类型),然后把它用相应的格式打印<BR></P></FONT><FONT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -