分享

Linux Kernel内核字节序源代码分析-swab.h和big_endian.h — ...

 岗西老蔡 2010-05-08

Linux Kernel内核字节序源代码分析-swab.h和big_endian.h

Linux 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()

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多