Linux Kernel内核字节序源代码分析-swab.h和big_endian.hLinux Kernel 2.6.14-内核字节序源代码分析-swab.h和big_endian.h
转载 **************************************************
----------------------------------------------------- 分析1: 以下据Linux Kernel中的注释:it doesn't pollute the POSIX namespace. Use these in the header files exported to user space.说明可用于用户空间。 typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; ------------自己加上的,为了后面的分析用 typedef __signed__ long long __s64; typedef unsigned long long __u64; ------------------------------------------------------ 分析2: 以下据Linux Kernel中的注释:These aren't exported outside the kernel to avoid name space clashes.只用于内核空间,以防命名冲突。 typedef signed char s8; typedef unsigned char u8; typedef signed short s16; typedef unsigned short u16; typedef signed int s32; typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; 附:typedef 的使用说明: 1.typedef跟变量一样有可视范围,并且内层的可以覆盖外层的。 例如: int main(void) { typedef int INT32; INT32 a; ... } void fun() { typedef long INT32; INT32 B; ... } main中的INT32为int型,而fun中的INT32为long型,但它们在自己的作用范围里独立起作用,互不干扰。 2.在同一作用范围内,不能用相同的名字来定义不同的数据类型。 如: int main(void) { typedef int INT32; typedef long INT32;//--->错误 ... } 即使是一模一样的也不能重复出现。 int main(void) { typedef int INT32; typedef int INT32;//--->错误 ... } 但在c++中,一模一样的可以重复出现。即:c++允许完全相同的typedef表达式多次出现。 3.比较1: 3-1. #define String char * String input,output; 其展开后的结果为: char * input,output;这时input为char *型,而output为char 型。因为*是右结合的。 3-2. typedef char * String; String input,output; 其展开后的结果为: char * input, *output; input ,output均为char *型。 typedef定义的类型对每一个变量都起作用。 比较2: #define INT32 int unsigned INT32 a;-------->这是对的。可以组合使用。 typedef int INT32; unsigned INT32 a;-------->这是错的,typedef不可以组合使用。 4.一个难点: typedef char * String; const String s; 问:展开后到底是const char * s; 还是char * const s; 答:展开后是char * const s; 原因:const 修饰的为String,而String为一个指针,所以const就修饰指针去了。 *************************************************** -------------------__swab16()---------------------- \byteorder\swab.h的源代码 #define ___swab16(x) \ ({ \ __u16 __x = (x); \ ((__u16)( \ (((__u16)(__x) & (__u16)0x00ffU) << 8) | \ (((__u16)(__x) & (__u16)0xff00U) >> 8) )); \ }) 分析: 1.__x与x,中间临时变量用同名,但前面加上“__” 2.U为无符号数,0x00ffU,注意数字部分用小写,U用大写,前面加0x 3.代码精彩之处为:先用(__u16)(__x) & (__u16)(0x00ffU)进行类型转换,再用移位运算。 ((__u16)(__x) & (__u16)0x00ffU) << 8) 和((__u16)(__x) & (__u16)0xff00U) >> 8) 两者结果再用或运算。 4.___swab16()前面有三个下划线,而不是两根下划线。 5.此处的宏定义为小写,即是将其视为函数来处理。 -----------------------___swab32()-------------------- #define ___swab32(x) \ ({ \ __u32 __x = (x); \ ((__u32)( \ (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | \ (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | \ (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | \ (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); \ }) 分析: 1.为长整型,UL,比如说:0x000000ffUL 2.这种很长的宏: 一要注意强制类型转换; 二要注意U,UL,ULL标志其数据类型; 三要注意宏内最后用‘;’结尾,宏外用({ 宏体部分}); 四要注意每行用\ 来表示续行。 3.写法上注意对称。中间临时变量用双下划线__x,而函数则用三下划线,如:___swab32()。 ----------------------___swab64()---------------- #define ___swab64(x) \ ({ \ __u64 __x = (x); \ ((__u64)( \ (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \ (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \ (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \ (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \ (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \ (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \ (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \ }) 主干部分源代码分析同上。 #if defined(__KERNEL__) #define swab16 __swab16 #define swab32 __swab32 #define swab64 __swab64 ... ... #endif Linux Kernel代码风格: 1.先对__fun()或___fun()编写实现代码; 2.再用宏定义fun()来替换__fun() ___fun(); ***************************************************** ----------------___constant_swab16()---------------- #define ___constant_swab16(x) \ ((__u16)( \ (((__u16)(x) & (__u16)0x00ffU) << 8) | \ (((__u16)(x) & (__u16)0xff00U) >> 8) )) -----------___constant_swab32()----------------------- #define ___constant_swab32(x) \ ((__u32)( \ (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ (((__u32)(x) & (__u32)0xff000000UL) >> 24) )) ------------___constant_swab64()--------------------- #define ___constant_swab64(x) \ ((__u64)( \ (__u64)(((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \ (__u64)(((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \ (__u64)(((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \ (__u64)(((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) | \ (__u64)(((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) | \ (__u64)(((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ (__u64)(((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \ (__u64)(((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56) )) 分析: 算法与上面的___swab16(),___swab32(),___swab64()一样。 只不过这里里是常量而矣。 ***************************************************** ------__arch__swab16()--__arch__swab16()--__arch__swab16()------ Linux Kernel 2.6.14中的对以下的源代码的解释: provide defaults when no architecture-specific optimization is detected。用于无体系结构优化的字节交换代码。 #ifndef __arch__swab16 #define __arch__swab16(x) ({ __u16 __tmp = (x) ; ___swab16(__tmp); }) #endif #ifndef __arch__swab32 #define __arch__swab32(x) ({ __u32 __tmp = (x) ; ___swab32(__tmp); }) #endif #ifndef __arch__swab64 #define __arch__swab64(x) ({ __u64 __tmp = (x) ; ___swab64(__tmp); }) #endif ***************************************************** ------------------指针型的字节交换宏--------------------- #ifndef __arch__swab16p #define __arch__swab16p(x) __arch__swab16(*(x)) #endif #ifndef __arch__swab32p #define __arch__swab32p(x) __arch__swab32(*(x)) #endif #ifndef __arch__swab64p #define __arch__swab64p(x) __arch__swab64(*(x)) #endif 分析同上,只是这里将x视为一个指针。 ***************************************************** -----------------存放字节交换结果型宏----------------- #ifndef __arch__swab16s #define __arch__swab16s(x) do { *(x) = __arch__swab16p((x)); } while (0) #endif #ifndef __arch__swab32s #define __arch__swab32s(x) do { *(x) = __arch__swab32p((x)); } while (0) #endif #ifndef __arch__swab64s #define __arch__swab64s(x) do { *(x) = __arch__swab64p((x)); } while (0) #endif 分析: 1.x为一个指针,将该指针所指向的内存单元数据送入指针型的字节交换宏__arch_swab??p(),将交换后的结果又存入该指针所指向的内存单元。 ***************************************************** ----------------__fswab16(__u16 x)------------------------------- static __inline__ __attribute_const__ __u16 __fswab16(__u16 x) { return __arch__swab16(x); } --------------__swab16p(const __u16 *x)------------------------- static __inline__ __u16 __swab16p(const __u16 *x) { return __arch__swab16p(x); } --------------------__swab16s(__u16 *addr)---------------------- static __inline__ void __swab16s(__u16 *addr) { __arch__swab16s(addr); } 分析: 1.对比: const __u16 * 和 __u16*不同之处。查看一下前面的代码就懂了。 ------------------------__fswab32(__u32 x)----------------- { static __inline__ __attribute_const__ __u32 __fswab32(__u32 x) { return __arch__swab32(x); } -------------------__swab32p(const __u32 *x)---------------- static __inline__ __u32 __swab32p(const __u32 *x) { return __arch__swab32p(x); } 说明:typedef unsigned int __u32;然后在这里将const__u32*进行组合使用。前面已经说明,typedef 不能组合使用。这里,将const 与typedef组合运用,自己好好注意这一个细节。 -------------------------__swab32s(__u32 *addr)----------------- static __inline__ void __swab32s(__u32 *addr) { __arch__swab32s(addr); } #if defined(__KERNEL__) ... ... #define swab16p __swab16p #define swab32p __swab32p #define swab64p __swab64p #define swab16s __swab16s #define swab32s __swab32s #define swab64s __swab64s #endif 对const的解释: 1.对const的讨论: 1-1. const int a=1; a++;-------------->错,a定义为一个常量了,所以a值不能改变。 1-2. int a=0; const int *p = &a; (*p)=1;------------>error,const修饰p所指向的对象,所以(*p)值不能改变。 1-3. int a=0,b=1; int * const p=&a; (*p)=1;----------->Ok p=&b;------------->Error 此处const修饰p,p所指向的值可以改变,但p自身的值不能被改变。 1-4. int a=0,b=1; const int * const p=&a; (*p)=1;----------->error p=&b;------------->Error 这里有两个const,一个修饰指针p,另一个修饰p所指向的int值。 2.对const的应用 在函数的参数中,如果我们希望函数只能引用指针所指向的内容,而不能改变其,这时可动用const 比如: int memcpy(const void *s1,const void *s2,size_t n); s1,s2所指向的内容只能读取,而不能被修改。若程序员不小心修改了其值,编译器会报错。 3.比较c++和c对const用法的不同之处: 3-1.c++能够把已用常量赋值的const变量看作编译时期的常数,c没有这种功能。 如: const int BUFSIZE = 1024; char buf[BUFSIZE];---------->Valid in C++ but illegal in C 3-2.c++默认const变量的链接性质为内部的,而c则相反,默认是外部的。 const int a=0; int main(){} 在c中,a为外部的链接,即其他的文件在代码 能够访问到它。而在c++中,a就默认为内部的链接,除非加上extern修饰词,否则其它的文件是看不到const变量a的。 3-3.c只能允许用常量来初始化const外部变量,c++则没有这种限制。 int f(void) const int a=f();--------->Valid in C++,but illegal in c int main() |
|