一行代码 [转]
时间:2006-06-20 来源:agg230
转自:www.chinaunix.net
----------------------------------------------------------------------------
#define offsetof(s, m) (size_t)(&(((s *)0)->;m))
这是offsetof的标准实现,主要是计算出结构体里成员的相对地址偏移量。
这里使用0只是一个使用的技巧,方便计算出偏移量。
#define offsetof(s, m) (size_t)(&(((s *)0)->;m))
这个宏用来求一个结构体成员相对于这个结构体首地址的偏移量,
例如:
struct zhx{int lanjuan;};
这个结构体里的成员lanjuan,它的相对偏移量就是4;
这个宏里的0是地址,(s *)0,这一步是把从0这个地址开始的一块大小的内存解释成这个结构体类型,&(((s *)0)->;m),这一步是取这个结构体程序m的地址,结合zhx这个结构体的例子,如果取成员lanjuan的地址,这个地址当然是4,对吧! 也就是说,通过这个技巧,我们可以很方便的得到了这个成员偏移量。
size_t其实就是无符号整形,也就是把上面得到的那个地址转成无符号整形
设有结构变量
struct tagX
{
......
<typeY>; y;
......
}x;
其中 typeY 是任意一个合法的类型名。
假设 ptrx 是指向 x 的指针。
那么,分量 y 的偏移量是指:“类型 tagX 的任意一个实例的地址与其分量 y 的地址的差”。
对于实例 x 来说,就是 &(ptrx->;y) - ptrx。
------------------------- ^ ------ ^
---------------------- 实例的地址 分量的地址
如果我们用 offset 来表示这个差值,就有
offset = &(ptrx->;y) - ptrx
这一点是显而易见的。
特别的,当 ptrx 等于 0 时(虽然事实上 ptrx 永远也不会等于 0 ),
我们有:
offset = &( 0->;y )
由于常量 0 的类型必须明确指定,所以就写作
offset = &( ((struct tagX *)0) ->; y )
说到这儿就比较明显了,如果我们定义宏
# define offset (&( ((struct tagX *)0) ->; y ) )
那么该宏的值就是 struct tagX 结构中的分量 y 相对于实例首址的偏移量。
其中 tagX 和 y 只是一个例子,一个更广泛使用的做法是用含有参数的宏将
tagX 和 y 代换:
# define offset( tagX, y ) ( &( ((tagX *)0) ->; y )
至于 size_t,它表示一个尺寸的类型,在大多数的系统中,它是基本类型
unsigned int 的一个宏。
--------------------------------------------------------------------------------
发表主题: c中怎么表示16进制的字符串
或者怎么把一串16进制的或者2进制的数字写到char 数组里面
for examele 40 3c 需要写到char [2]里面去
无双 答:char a[]={0x40,0x3c}; 注意因为中间可能会有\0 所以这时使用strcpy等要小心 它们都是遇到\0就认为字符串结束
----------------------------------------------------------------------------------
typedef会在预处理中处理掉吗?
无双答:http://e.swjtu.edu.cn/jiaowu/jxzd/wykj/cpro/chp9/9-10-1.htm
typedef与#define有相似之处,
如:typedef int COUNT;和 #define COUNT int 的作用都是用COUNT代表int。但事实上,它们二者是不同的。
#define在预编译时处理的,它只能作简单的字符串替换,而typedef是在编译时处理的。实际上它并不是作简单的字符串替换,例如:typedef int NUM[10];并不是用NUM[10]去代替int,而是采用如同定义变量的方法那样来定义一个类型(就是前面介绍过的将原来的变量名换成类型名)。
-----------------------------------------------------------------------
const可用来限制指针不可变。也就是说指针指向的内存地址不可变,但可以随意改变该地址指向的内存的内容。
----------------------------------------------------------------------------
#define offsetof(s, m) (size_t)(&(((s *)0)->;m))
这是offsetof的标准实现,主要是计算出结构体里成员的相对地址偏移量。
这里使用0只是一个使用的技巧,方便计算出偏移量。
#define offsetof(s, m) (size_t)(&(((s *)0)->;m))
这个宏用来求一个结构体成员相对于这个结构体首地址的偏移量,
例如:
struct zhx{int lanjuan;};
这个结构体里的成员lanjuan,它的相对偏移量就是4;
这个宏里的0是地址,(s *)0,这一步是把从0这个地址开始的一块大小的内存解释成这个结构体类型,&(((s *)0)->;m),这一步是取这个结构体程序m的地址,结合zhx这个结构体的例子,如果取成员lanjuan的地址,这个地址当然是4,对吧! 也就是说,通过这个技巧,我们可以很方便的得到了这个成员偏移量。
size_t其实就是无符号整形,也就是把上面得到的那个地址转成无符号整形
设有结构变量
struct tagX
{
......
<typeY>; y;
......
}x;
其中 typeY 是任意一个合法的类型名。
假设 ptrx 是指向 x 的指针。
那么,分量 y 的偏移量是指:“类型 tagX 的任意一个实例的地址与其分量 y 的地址的差”。
对于实例 x 来说,就是 &(ptrx->;y) - ptrx。
------------------------- ^ ------ ^
---------------------- 实例的地址 分量的地址
如果我们用 offset 来表示这个差值,就有
offset = &(ptrx->;y) - ptrx
这一点是显而易见的。
特别的,当 ptrx 等于 0 时(虽然事实上 ptrx 永远也不会等于 0 ),
我们有:
offset = &( 0->;y )
由于常量 0 的类型必须明确指定,所以就写作
offset = &( ((struct tagX *)0) ->; y )
说到这儿就比较明显了,如果我们定义宏
# define offset (&( ((struct tagX *)0) ->; y ) )
那么该宏的值就是 struct tagX 结构中的分量 y 相对于实例首址的偏移量。
其中 tagX 和 y 只是一个例子,一个更广泛使用的做法是用含有参数的宏将
tagX 和 y 代换:
# define offset( tagX, y ) ( &( ((tagX *)0) ->; y )
至于 size_t,它表示一个尺寸的类型,在大多数的系统中,它是基本类型
unsigned int 的一个宏。
--------------------------------------------------------------------------------
发表主题: c中怎么表示16进制的字符串
或者怎么把一串16进制的或者2进制的数字写到char 数组里面
for examele 40 3c 需要写到char [2]里面去
无双 答:char a[]={0x40,0x3c}; 注意因为中间可能会有\0 所以这时使用strcpy等要小心 它们都是遇到\0就认为字符串结束
----------------------------------------------------------------------------------
typedef会在预处理中处理掉吗?
无双答:http://e.swjtu.edu.cn/jiaowu/jxzd/wykj/cpro/chp9/9-10-1.htm
typedef与#define有相似之处,
如:typedef int COUNT;和 #define COUNT int 的作用都是用COUNT代表int。但事实上,它们二者是不同的。
#define在预编译时处理的,它只能作简单的字符串替换,而typedef是在编译时处理的。实际上它并不是作简单的字符串替换,例如:typedef int NUM[10];并不是用NUM[10]去代替int,而是采用如同定义变量的方法那样来定义一个类型(就是前面介绍过的将原来的变量名换成类型名)。
-----------------------------------------------------------------------
const可用来限制指针不可变。也就是说指针指向的内存地址不可变,但可以随意改变该地址指向的内存的内容。
CODE:
[Copy to clipboard]
void main(void)
{
char* const str = "Hello, World"; //常指针,指向字符串
*str = 'M'; //可以改变字符串内容
str = "Bye, World"; //错误,如能改变常指针指向的内存地址
} const也可用来限制指针指向的内存不可变,但指针指向的内存地址可变。
{
char* const str = "Hello, World"; //常指针,指向字符串
*str = 'M'; //可以改变字符串内容
str = "Bye, World"; //错误,如能改变常指针指向的内存地址
} const也可用来限制指针指向的内存不可变,但指针指向的内存地址可变。
CODE:
[Copy to clipboard]
void main(void)
{
const char* str = "Hello, World"; //指针,指向字符串常量
*str = 'M'; //错误,不能改变字符串内容
str = "Bye, World"; //修改指针使其指向另一个字符串
*str = 'M'; //错误,仍不能改变字符串内容
} 看完上面的两个例子,是不是糊涂了?告诉你一个诀窍,在第一个例子中,const用来修饰指针str,str不可变(也就是指向字符的常指针);第二个例子中,const用来修饰char*,字符串char*不可变(也就是指向字符串常量的指针)。
{
const char* str = "Hello, World"; //指针,指向字符串常量
*str = 'M'; //错误,不能改变字符串内容
str = "Bye, World"; //修改指针使其指向另一个字符串
*str = 'M'; //错误,仍不能改变字符串内容
} 看完上面的两个例子,是不是糊涂了?告诉你一个诀窍,在第一个例子中,const用来修饰指针str,str不可变(也就是指向字符的常指针);第二个例子中,const用来修饰char*,字符串char*不可变(也就是指向字符串常量的指针)。
相关阅读 更多 +