linux设备驱动程序学习(7)-内核的数据类型 - linux设备驱动程序 - tekkaman ninja.htm

来自「Linux设备驱动程序学习(7)-内核的数据类型 - Linux设备驱动程序.r」· HTM 代码 · 共 943 行 · 第 1/5 页

HTM
943
字号
                              </DIV>
                              <DIV>将linux 
                              移植到新的体系结构时,开发者遇到的若干问题都与不正确的数据类型有关。坚持使用严格的数据类型和使用 
                              <FONT color=#ff0000>-Wall 
                              -Wstrict-prototypes</FONT> 进行编译可能避免大部分的 bug。</DIV>
                              <P>内核数据使用的数据类型主要分为 3 个类型: <FONT color=#0000ff>标准 C 
                              语言类型</FONT>、<FONT 
                              color=#0000ff>确定大小的类型</FONT>和<FONT 
                              color=#0000ff>特定内核对象的类型</FONT>。 
                              <HR id=null>
                              <STRONG><FONT color=#0000ff size=3>标准 C 
                              语言类型</FONT></STRONG> 
                              <P></P>
                              <P>当需要“一个2字节填充符”或“用一个4字节字串来代表某个东西”,就不能使用标准C语言类型,因为在不同的体系结构,C 
                              语言的数据类型所占的空间大小不同。后面的datasize 程序实验展示了用户空间各种 C 
                              的数据类型在当前平台所占空间的大小。而且有的构架,内核空间和用户空间的C 
                              数据类型所占空间大小也可能不同。kdatasize模块显示了当前模块的内核空间C 
                              数据类型所占空间大小。</P>
                              <P>尽管概念上地址是指针,但使用一个无符号整型可以更好地实现内存管理; <FONT 
                              color=#ff0000>内核把物理内存看成一个巨型数组, 
                              内存地址就是该数组的索引</FONT>。 
                              我们可以方便地对指针取值,但直接处理内存地址时,我们几乎从不会以这种方式对他取值。使用一个整数类型避免了这种取值,因此避免了 
                              bug。所以,利用至少在 Linux 
                              目前支持的所有平台上,指针和长整型始终是相同大小的这一事实,<FONT 
                              color=#ff0000>内核中内存地址常常是 unsigned long</FONT>。</P>
                              <P>C99 标准定义了 intptr_t 和 uintptr_t 
                              类型,它们是能够保存指针值的整型变量。但没在 2.6 内核中几乎没使用。 
                              <HR id=null>

                              <P></P><FONT color=#0000ff 
                              size=3><STRONG>确定大小的类型</STRONG></FONT> 
                              <P>当需要知道你定义的数据的大小时,可以使用内核提供的下列数据类型(所有的数据声明在 
                              &lt;asm/types.h&gt;, 被包含在 &lt;linux/types.h&gt; ): 

                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: #000000"><FONT face=新宋体>u8<SPAN 
                                style="COLOR: #0000cc">;</SPAN> <SPAN 
                                style="COLOR: #ff9900">/* unsigned byte (8 bits) 
                                */</SPAN><BR>u16<SPAN 
                                style="COLOR: #0000cc">;</SPAN> <SPAN 
                                style="COLOR: #ff9900">/* unsigned word (16 
                                bits) */</SPAN><BR>u32<SPAN 
                                style="COLOR: #0000cc">;</SPAN> <SPAN 
                                style="COLOR: #ff9900">/* unsigned 32-bit value 
                                */</SPAN><BR>u64<SPAN 
                                style="COLOR: #0000cc">;</SPAN> <SPAN 
                                style="COLOR: #ff9900">/* unsigned 64-bit value 
                                */</SPAN></FONT></SPAN></CODE></P>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: #000000"><FONT face=新宋体><SPAN 
                                style="COLOR: #ff9900"><FONT 
                                color=#ff9900>/*虽然<FONT 
                                face="Courier New">很少需要有符号类型,但是如果需要,只要用 s 代替 
                                u*/</FONT></FONT></SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
                              <P>若一个用户空间程序需要使用这些类型,可在符号前加一个双下划线: __u8和其它类型是独立于 
                              __KERNEL__ 定义的。</P>
                              <P>这些类型是 Linux 特定的,它们妨碍了移植软件到其他的 Unix 机器。新的编译器系统支持 
                              C99-标准 类型,如 uint8_t 和 uint32_t。若考虑移植性,使用这些类型比 
                              Linux特定的变体要好。 
                              <HR id=null>
                              <FONT color=#0000ff 
                              size=3><STRONG>接口特定的类型(</STRONG><FONT 
                              color=#660099>_t 
                              类型</FONT><STRONG>)</STRONG></FONT> 
                              <P></P>
                              <DIV>
                              <P>内核中最常用的数据类型由它们自己的 typedef 
                              声明,阻止了任何移植性问题。“接口特定(interface-specific)”由某个库定义的一种数据类型, 
                              以便为了某个特定的数据结构提供接口。很多 _t 类型在 &lt;linux/types.h&gt; 
                              中定义。</P>
                              <P><FONT 
                              color=#660099>注意:近来已经很少定义新的接口特定的类型。有许多内核开发者已经不再喜欢使用 
                              typedef 
                              语句,他们宁愿看到代码中直接使用的真实类型信息。很多老的接口特定类型在内核中保留,他们不会很快消失。</FONT></P>
                              <P>即使没有定义接口特定类型,也应该始终是用和内核其他部分保持一致、适当的数据类型。只要驱动使用了这种“定制”类型的函数,但又不遵照约定,编译器会发出警告,这时使用 
                              -Wall 编译器选项并小心去除所有的警告,就可以确信代码的可移植性了。</P>
                              <P>_t 类型的主要问题是:打印它们时,常常不容易选择正确的 printk 或 printf 
                              格式。打印接口特定的数据的最好方法是:将其强制转换为可能的最大类型(常常是 long 或 
                              unsigned long ) 并用相应的格式打印。 
                              <HR id=null>
                              <FONT color=#0000ff 
                              size=4><STRONG>其他移植性问题</STRONG></FONT> 
                              <P></P>
                              <P><FONT 
                              color=#ff0000>移植的一个通常规则是:避免使用显式的常量值,要使用预处理宏使常量值参数化。</FONT></P>
                              <P><A name=TimeIntervals.sect></A><FONT 
                              color=#0000ff 
                              size=3><STRONG>时间间隔</STRONG></FONT></P>
                              <DIV class=sect2 lang=zh-cn>
                              <P>当处理时间间隔时,不要假定每秒的jiffies个数,不是每个 Linux 
                              平台都以固定的速度运行.当计算时间间隔时,要使用 HZ ( 每秒的定时器中断数 ) 
                              来标定你的时间。s3c2410的HZ值默认为200。</P>
                              <P><A name=PageSize.sect></A><FONT color=#0000ff 
                              size=3><STRONG>页大小</STRONG></FONT></P></DIV>
                              <DIV class=sect2 lang=zh-cn>
                              <P>当使用内存时,记住一个内存页是 PAGE_SIZE 字节, 不是 4KB。相关的宏定义是 
                              PAGE_SIZE 和 PAGE_SHIT(包含将一个地址移位来获得它的页号的位数),在 <FONT 
                              color=#0000ff>&lt;asm/page.h&gt;</FONT> 
                              中定义。如果用户空间程序需要这些信息,可以使用 getpagesize 库函数。</P>
                              <P>若一个驱动需要 16 KB 来暂存数据,一个可移植得解决方法是 get_order: 
                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: #000000"><FONT face=新宋体><SPAN 
                                style="COLOR: #0000cc">#</SPAN><SPAN 
                                style="COLOR: #ff0000">include</SPAN> <SPAN 
                                style="COLOR: #0000cc">&lt;</SPAN><SPAN 
                                style="COLOR: #0000ff">asm</SPAN><SPAN 
                                style="COLOR: #0000cc">/</SPAN>page<SPAN 
                                style="COLOR: #0000cc">.</SPAN>h<SPAN 
                                style="COLOR: #0000cc">&gt;</SPAN><BR><SPAN 
                                style="COLOR: #0000ff">int</SPAN> order <SPAN 
                                style="COLOR: #0000cc">=</SPAN> get_order<SPAN 
                                style="COLOR: #0000cc">(</SPAN>16<SPAN 
                                style="COLOR: #0000cc">*</SPAN>1024<SPAN 
                                style="COLOR: #0000cc">)</SPAN><SPAN 
                                style="COLOR: #0000cc">;</SPAN><BR>buf <SPAN 
                                style="COLOR: #0000cc">=</SPAN> 
                                get_free_pages<SPAN 
                                style="COLOR: #0000cc">(</SPAN>GFP_KERNEL<SPAN 
                                style="COLOR: #0000cc">,</SPAN> order<SPAN 
                                style="COLOR: #0000cc">)</SPAN><SPAN 
                                style="COLOR: #0000cc">;</SPAN><SPAN 
                                style="COLOR: #ff9900">/*get_order 的参数必须是 2 
                                的幂*/</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P></DIV>
                              <DIV class=sect2 lang=zh-cn>
                              <DIV class=titlepage>
                              <DIV>
                              <DIV>
                              <H3 class=title><A name=ByteOrder.sect></A><FONT 
                              color=#0000ff 
                              size=3>字节序</FONT></H3></DIV></DIV></DIV>
                              <P>不要假设字节序。 代码应该编写成不依赖所操作数据的字节序的方式。</P>
                              <P>头文件 &lt;asm/byteorder.h&gt; 定义:</P>
                              <P>
                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: #000000"><FONT face=新宋体><SPAN 
                                style="COLOR: #0000cc">#</SPAN><SPAN 
                                style="COLOR: #ff0000">ifdef</SPAN> 
                                __ARMEB__<BR><SPAN 
                                style="COLOR: #0000cc">#</SPAN><SPAN 
                                style="COLOR: #ff0000">include</SPAN> <SPAN 
                                style="COLOR: #0000cc">&lt;</SPAN>linux<SPAN 
                                style="COLOR: #0000cc">/</SPAN>byteorder<SPAN 
                                style="COLOR: #0000cc">/</SPAN>big_endian<SPAN 
                                style="COLOR: #0000cc">.</SPAN>h<SPAN 
                                style="COLOR: #0000cc">&gt;</SPAN><BR><SPAN 
                                style="COLOR: #0000cc">#</SPAN><SPAN 
                                style="COLOR: #0000ff">else</SPAN><BR><SPAN 
                                style="COLOR: #0000cc">#</SPAN><SPAN 
                                style="COLOR: #ff0000">include</SPAN> <SPAN 
                                style="COLOR: #0000cc">&lt;</SPAN>linux<SPAN 
                                style="COLOR: #0000cc">/</SPAN>byteorder<SPAN 
                                style="COLOR: #0000cc">/</SPAN>little_endian<SPAN 
                                style="COLOR: #0000cc">.</SPAN>h<SPAN 
                                style="COLOR: #0000cc">&gt;</SPAN><BR><SPAN 
                                style="COLOR: #0000cc">#</SPAN><SPAN 
                                style="COLOR: #ff0000">endif</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
                              <P>在<FONT face=新宋体><SPAN 
                              style="COLOR: #0000cc">&lt;</SPAN>linux<SPAN 
                              style="COLOR: #0000cc">/</SPAN>byteorder<SPAN 
                              style="COLOR: #0000cc">/</SPAN>big_endian<SPAN 
                              style="COLOR: #0000cc">.</SPAN>h<SPAN 
                              style="COLOR: #0000cc">&gt;<FONT 
                              color=#000000>中定义了</FONT></SPAN></FONT>__BIG_ENDIAN&nbsp;,而在<FONT 
                              face=新宋体>&lt;linux<SPAN 
                              style="COLOR: #0000cc">/</SPAN>byteorder<SPAN 
                              style="COLOR: #0000cc">/</SPAN>little_endian<SPAN 
                              style="COLOR: #0000cc">.</SPAN>h<SPAN 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?