Linux Kernel內(nèi)核字節(jié)序源代碼分析-swab.h和big_endian.hLinux Kernel 2.6.14-內(nèi)核字節(jié)序源代碼分析-swab.h和big_endian.h
轉(zhuǎn)載 **************************************************
----------------------------------------------------- 分析1: 以下?lián)﨤inux 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: 以下?lián)﨤inux Kernel中的注釋:These aren't exported outside the kernel to avoid name space clashes.只用于內(nèi)核空間,,以防命名沖突。 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跟變量一樣有可視范圍,,并且內(nèi)層的可以覆蓋外層的,。 例如: int main(void) { typedef int INT32; INT32 a; ... } void fun() { typedef long INT32; INT32 B; ... } main中的INT32為int型,而fun中的INT32為long型,但它們在自己的作用范圍里獨立起作用,,互不干擾,。 2.在同一作用范圍內(nèi),不能用相同的名字來定義不同的數(shù)據(jù)類型,。 如: int main(void) { typedef int INT32; typedef long INT32;//--->錯誤 ... } 即使是一模一樣的也不能重復出現(xiàn),。 int main(void) { typedef int INT32; typedef int INT32;//--->錯誤 ... } 但在c++中,一模一樣的可以重復出現(xiàn),。即:c++允許完全相同的typedef表達式多次出現(xiàn),。 3.比較1: 3-1. #define String char * String input,output; 其展開后的結(jié)果為: char * input,output;這時input為char *型,而output為char 型,。因為*是右結(jié)合的,。 3-2. typedef char * String; String input,output; 其展開后的結(jié)果為: 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為無符號數(shù),,0x00ffU,注意數(shù)字部分用小寫,,U用大寫,,前面加0x 3.代碼精彩之處為:先用(__u16)(__x) & (__u16)(0x00ffU)進行類型轉(zhuǎn)換,再用移位運算,。 ((__u16)(__x) & (__u16)0x00ffU) << 8) 和((__u16)(__x) & (__u16)0xff00U) >> 8) 兩者結(jié)果再用或運算,。 4.___swab16()前面有三個下劃線,而不是兩根下劃線,。 5.此處的宏定義為小寫,,即是將其視為函數(shù)來處理。 -----------------------___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.這種很長的宏: 一要注意強制類型轉(zhuǎn)換; 二要注意U,,UL,,ULL標志其數(shù)據(jù)類型,; 三要注意宏內(nèi)最后用‘;’結(jié)尾,,宏外用({ 宏體部分}),; 四要注意每行用\ 來表示續(xù)行。 3.寫法上注意對稱,。中間臨時變量用雙下劃線__x,而函數(shù)則用三下劃線,,如:___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()編寫實現(xiàn)代碼,; 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,。用于無體系結(jié)構優(yōu)化的字節(jié)交換代碼。 #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 ***************************************************** ------------------指針型的字節(jié)交換宏--------------------- #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視為一個指針,。 ***************************************************** -----------------存放字節(jié)交換結(jié)果型宏----------------- #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為一個指針,將該指針所指向的內(nèi)存單元數(shù)據(jù)送入指針型的字節(jié)交換宏__arch_swab??p(),,將交換后的結(jié)果又存入該指針所指向的內(nèi)存單元,。 ***************************************************** ----------------__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*進行組合使用,。前面已經(jīng)說明,typedef 不能組合使用,。這里,,將const 與typedef組合運用,自己好好注意這一個細節(jié),。 -------------------------__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的應用 在函數(shù)的參數(shù)中,,如果我們希望函數(shù)只能引用指針所指向的內(nèi)容,而不能改變其,,這時可動用const 比如: int memcpy(const void *s1,const void *s2,size_t n); s1,s2所指向的內(nèi)容只能讀取,,而不能被修改。若程序員不小心修改了其值,,編譯器會報錯,。 3.比較c++和c對const用法的不同之處: 3-1.c++能夠把已用常量賦值的const變量看作編譯時期的常數(shù),c沒有這種功能,。 如: const int BUFSIZE = 1024; char buf[BUFSIZE];---------->Valid in C++ but illegal in C 3-2.c++默認const變量的鏈接性質(zhì)為內(nèi)部的,,而c則相反,默認是外部的,。 const int a=0; int main(){} 在c中,,a為外部的鏈接,即其他的文件在代碼 能夠訪問到它,。而在c++中,,a就默認為內(nèi)部的鏈接,除非加上extern修飾詞,,否則其它的文件是看不到const變量a的,。 3-3.c只能允許用常量來初始化const外部變量,c++則沒有這種限制,。 int f(void) const int a=f();--------->Valid in C++,but illegal in c int main() |
|