struct 中的member variable 的offset的宏定义

本文详细解释了C语言中offsetof宏的定义与使用方法,并通过具体示例帮助读者理解如何利用该宏来计算结构体成员变量的偏移量。

 

struct 中的member variable 的offset的宏定义

#define offsetof(s,m)   (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))

定义:#define offsetof(type, f) ((size_t) ((char *)&((type *)0)->f - (char *)(type *)0))

解释:

【akirya】:
先将0转化为 type*类型的指针,然后取得成员变量的地址,在减去0
最后得到的就是 成员变量的偏移地址.
【Jarrylogin】:
0转化为 type*类型的指针是不是空指针?它如何知道f
【qwe896】:
http://c-faq-chn.sourceforge.net/ccfaq/node30.html
我在上面网页中找到的这个解释,你看是不是正确:
3.12 如何确定域在结构中的字节偏移?
ANSI C在<stddef.h> 中定义了offsetof() 宏, 用 offsetof(struct s, f) 可以计算出域 f 在结构 s 中的偏移量。 如果出于某种原因, 你需要自己实现这个功能, 可以使用下边这样的代码:
#define offsetof(type, f) ((size_t)
    ((char *)&((type *)0)->f - (char *)(type *)0))
这种实现不是 100% 的可移植; 某些编译器可能会合法地拒绝接受。
【akirya】:
你知道结构体怎么找到成员变量的么?
就是结构体对象的地址+偏移量;
struct type
{
int x;
int f;
};
type*p = new type;
printf("%d,%d/n",p,&(p->f));
这样的输出你能理解么
只不过那个宏 现将0转化为type*类型
只要不访问成员变量就不会引起访问违规.
to  qwe896(老蒋)
能不能列举一个 无法编译这样代码的C编译器?
【Chiyer】:
#define offsetof(s,m) (size_t)&(((s *)0)->m)
然后到网上查了一下,发现还真的是很有用,附带一位大侠的解说:
  struct   AAA  
  {  
  int   i;  
  int   j;  
  };  
  struct AAA *pAAA;  
  pAAA=new AAA;  
  这时,pAAA实际上是一个Pointer, 指向某一确定的内存地址,比如0x1234;  
  而 pAAA->i 整体是一个int型变量,其地址是&(pAAA->i) ,'&'为取址运算符;  
  那么&(pAAA->i)一定等于0x1234,因为i是结构体AAA的第一个元素。  
  而&(pAAA->j)一定是0x1234 + 0x4 = 0x1238; 因为sizeof(int) = 4;
  这个做法的巧妙之处就是:它把“0”作为上例中的pAAA,那么 &(pAAA->j)就是j的  
  offset啦
  解析结果是:  
  (s   *)0 ,将 0 强制转换为Pointer to   "s"    
  可以记 pS = (s *)0 ,pS是指向s的指针,它的值是0;  
  那么pS->m就是m这个元素了,而&(pS->m)就是m的地址,而在本例中就是offset啦  
  再把结果强制转换为size_t型的就OK 了,size_t其实也就是int啦!!
【ky310】:
支持一下
【yulefox】:
#define offsetof(type, f) ((size_t) /
((char *)&((type *)0)->f - (char *)(type *)0))
type为class或struct类型名,f为type类型成员。现在要确定f在type对象模型中的空间位置,很自然地想到将一个type类型对象起始地址设为0,再计算出f的起始地址,二者之差即为f在type中的位置:
type类型对象:(type *)0
对象起始地址:(char *)&((type *)0),char *是为了保证字节为单位,只要你不试图去改变它,这样是合法的
f的起始地址:((char *)&((type *)0)->f
【Jarrylogin】:
越来越混了
(s   *)0 ,将 0 强制转换为Pointer to   "s"    
  可以记 pS = (s *)0 ,pS是指向s的指针,它的值是0;  
pS->m就是m这个元素?0明显不等于0x1234,那如何找到m,是不是我理解错误?
【Jarrylogin】:
只要不访问成员变量就不会引起访问违规.怎么理解?
【akirya】:
int *p=0;
*p=1;访问违规
pS->m就是m这个元素?0明显不等于0x1234,那如何找到m,是不是我理解错误?
在这个时候编译器会将计算this+偏移地址
pS->m=0;会对this+偏移地址的内容进行赋值
【Jarrylogin】:
你是说 0在此处时编译器会将它看成this指针?
【akirya】:
说习惯了this是指结构体变量的地址.
不是看成
代码中 (type *)0 就是强制转换
&((type *)0)->f
这个是一部分
(char *)&((type *)0)->f
这个也是一部分
(char *)(type *)0)
分开看就容易理解了
【contain_universe】:
#define offsetof(type, f) ((size_t)((char *)&((type *)0)->f - (char *)(type *)0))
宏定义是:求得成员f在type变量中的偏移量
给你个调用实例
struct list{
  char ch;
  int  num;
  int  f;
}demo;
size_t offset = offsetof(demo, f);
上面说的也不错
【Jarrylogin】:
请问楼上此处0和this指针是如何联系上的?
【akirya】:
this指针是在struct内部使用的
外部用的话就是结构体的指针了,通常两个值是一样的
【Jarrylogin】:
我是问(type *)0和this指针是如何联系上的?我可能没有表述清楚
【akirya】:
struct type
{
int x;
int f;
};
type* p=(type *)0;
printf("%d",&(p->f));
这样能理解了么?

 

另一解:

#define   OFFSET(structure,   member)     ((int)   &((structure   *)0)->member)  
  0这里指的是指针0处,这样结构的第一个成员就与0对齐了,取member的地址当然就是偏移了。当然,该偏移不能直接用,需要强制转换为int。

进行编码规范: 1、标准变量类型 禁止使用C语言的标准变量类型。 请使用共通头文件“aip_common.h”中定义了标准类型,如下: #ifndef AIP_COMMON_H #define AIP_COMMON_H typedef unsigned char U1; typedef unsigned short U2; typedef unsigned int U4; typedef long unsigned int U8; typedef signed char S1; typedef signed short S2; typedef signed long S4; typedef signed long long S8; typedef U1* U1P; typedef U2* U2P; typedef U4* U4P; typedef U8* U8P; typedef S1* S1P; typedef S2* S2P; typedef S4* S4P; typedef S8* S8P; typedef void* VDP; #define U1_MAX 0xFFU #define U1_MIN 0x00U #define S1_MAX 0x7F #define S1_MIN 0x80 #define U2_MAX 0xFFFFU #define U2_MIN 0x0000U #define S2_MAX 0x7FFF #define S2_MIN 0x8000 #define U4_MAX 0xFFFFFFFFUL #define U4_MIN 0x00000000UL #define S4_MAX 0x7FFFFFFFL #define S4_MIN 0x80000000L #define U8_MAX 0xFFFFFFFFFFFFFFFFULL #define U8_MIN 0x0000000000000000ULL #define S8_MAX 0x7FFFFFFFFFFFFFFFLL #define S8_MIN 0x8000000000000000LL #define TRUE 1 #define FALSE 0 #define ST struct #define EN enum #endif /* AIP_COMMON_H */ 2、变量: Format type [dt][s][a][module][variable]; Length of Identifier 最多32个字符 [dt]变量类型 标准类型 u1, u2, u4, u8, s1, s2, s4, s8 结构体类型 st 枚举类型 en 共用体类型 MISRA-C中禁止使用 函数指针类型 fp 变量指针类型 u1p, u2p, u4p, s1p, s2p, s4p, s8p, stp 空指针类型 vdp [s]作用域 ※ 函数域内的自动变量 t 函数阈内的参数变量 a 文件阈内的static变量 s 文件域内外的extern变量 g [a]数组 ※ 维数=0 无修饰字符 维数=1 p 维数=n p[n] [module]模块名 [variable]变量名 有const修饰 只能使用大写字母 无const修饰 只能使用小写字母 3、函数 Format type [dt][s]_[module]function; Length of Identifier 最多32个字节 [dt]返回值类型 标准类型 u1, u2, u4, u8, s1, s2, s4, s8 结构体类型 st 枚举类型 en 共用体类型 MISRA-C中禁止使用 变量指针类型 u1p, u2p, u4p, s1p, s2p, s4p, s8p, stp 空指针类型 vdp [s]作用域 static函数仅在文件内 s extern函数在文件内外 g [module]模块名 [function]函数名 大小写字母均可使用 [parameter]形参名 3.3. 命名规则:遵从定义变量的命名格式 ※:函数原型声明时,必须定义形参。 ※函数内不会修改的参数,必须加上“const”修饰符。 4、注释必须是英文,不要使用“//”注释,不要跨行使用注释。在每一行,分别使用“/”和“/”来注释“/”后面和“/”的前面,插入空格 每个函数前面都要加注释,形如: /===================================================================================================================================/ /* Function Name: v_g_SYMBOL_saveFile / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Saves user-defined symbol pairs to Symbol.txt file after validation / / Arguments: const U2 *u2p_g_FILE_folder_path_p : Folder path / / const U2 u2p_a_SYMBOL_user_input : User input symbols / / Return: void / /===================================================================================================================================/ 5、{每个左大括号都要另起一行 6、所有判断语句,if while等只能是判断语句,不能嵌套函数 7、每个函数最多一个出口 8、返回值是一个变量,或者直接写一个值,不要写公式 9、结构体: Format typedef struct{ [member] … }ST_[module]_[variable]; Length of Identifier 最多32个字符 [module]模块名 [variable]变量名 只能使用大写字母 [member] 成员名称需要按照3.3. 变量的规定。 禁止使用位域类型定义。 不过,Micro Controller Vendor提供的Micro-Controller的控制寄存器定义除外。 10、不要用常数,用魔法数字,如果是全是常数的公式,可以在宏里面定义 分模块,分别给出每个文件的具体代码
最新发布
09-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值