首先我们要更正一个很熟悉的概念,那就是指针不仅仅是“地址”,指针还有一个很重要的特性,那就是“类型”

指针初始化时,“=”的右操作数必须为内存中数据的地址,不可以是变量,也不可以直接用整型地址值(但是 int *p = ; 除外,该语句表示指针为空);

所以 int *p = ; 这样的代码是不允许的。在C++里面直接是error的,即使在一些C编译器中以warning的形式提示,但是warning有的时候也很严重。所以这种东西不要用。从const int到int*是不存在隐士转换的。

正确的使用方法是 int *p = (int*); 这样就先使10这个地址增加一个类型,然后在赋值给int *p。看这句话的汇编:

00401048   mov         dword ptr [ebp-4],0Ah

就是把10放到p对应的内存空间去。


这里可以看出可以把一个地址加上一个类型,这样的话就构成了一个指针,但是这个指针类似一个常量,就像10这个立即数默认是int类型,不会产生代码,所以(int*)10也不会产生汇编代码。所以不会出现去访问内存的保护区域这种情况发生。

那么下面开始说利用宏定义求结构体成员偏移量

我们在书写C程序的时候,有时候需要根据结构体成员变量的地址,得到结构体的地址,特别是我们想用C来实现C++的继承特性的时候。
我们对问题的分析如下:

输入:一个结构体定义type,这个结构体中某个成员变量的名字member以及它的地址ptr
输出:包含此成员变量的结构体的地址

为了便于分析,我们给出一个实例来说明

struct father_t {
int a;
char *b;
double c;
}f;
char *ptr = &(f.b);
//而不是 ptr = f.b; 这里ptr是b的地址,而不是它指向的地址。
根据C语言对struct类型的存储特性,我们可以画这么一个图示:

注意:f.b是一个指针,指向char*b的第一个字符,&(f.b)是这个指针的地址。

通过分析图示,我们可以看出,我们只需要把当前知道的成员变量的地址ptr,减去它在结构体当中相对偏移量4就的到了结构体的地址(ptr-4)。

在linux当中对此有一个很好的宏可以使用,叫做 container_of, 放在 linux/kernel.h当中。它的定义如下所示:

#define offsetof(TYPE, MEMBER) ( (size_t) & ((TYPE *)0)->MEMBER )

注意:这个宏定义的输入是一个结构体的类型,这个结构体的一个成员变量。

宏功能:获得一个结构体变量成员在此结构体中的偏移量。

1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;
3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址,即相对于0的偏移量,要的就这个;
4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型,size_t应该最终为unsigned int类型。 此宏的巧妙之处在于将 0 转换成(TYPE*),这样结构体中成员的地址即为在此结构体中的偏移量。

这里只是利用0这个地址,使它具有类型,并没有访问0地址对应的内存空间里的数据,所以不会发生读写保护存储区这种情况。

#define offset(type, a) ( (unsigned int) &(((type*)0)->a) )

struct _test_
{
int a;
char x;
double d;
char ch[10];
}; int main()
{
cout << offset(struct _test_, ch) << endl;
return 0;
}

根据结构体内存对齐的方式,得到的结果正好是16。

参考文章:http://www.cnblogs.com/youxin/p/3348227.html

  

指针直接赋值为整型AND利用宏定义求结构体成员偏移量的更多相关文章

  1. go语言基础之结构体成员的使用指针变量

    1.结构体成员的使用:指针变量 示例: package main //必须有个main包 import "fmt" //定义一个结构体类型 type Student struct ...

  2. go 结构体定义和结构体指针

    结构体一个结构体(`struct`)就是一个字段的集合. 将来要使用它向java .C# 中的class 有相同的地位 struct 可以用来值传递 同时可以通过引用传递参数(地址) java C# ...

  3. iOS下单例模式实现(二)利用宏定义快速实现

    在上一节里提到了用利用gcd快速实现单例模式. 一个项目里面可能有好几个类都需要实现单例模式.为了更高效的编码,可以利用c语言中宏定义来实现. 新建一个Singleton.h的头文件. // @int ...

  4. swap 用指针交换两个整型数值

  5. [GO]结构体成员的使用:指针变量

    package main import "fmt" func main() { type student struct { id int name string sex byte ...

  6. 利用宏定义令iOS项目当中的NSLog不执行

    今天在博客园主页看到一篇帖子,提到NSLog消耗运行时性能: http://www.cnblogs.com/sunnyxx/p/3680623.html 解决方案如下,在​Prefix.pch文件当中 ...

  7. 利用宏定义实现C++程序在Unix和Win32环境下的通用性

    [转] 1.1. 宏定义软件的代码,从跨平台的角度来看,可以分为平台相关的和平台无关的.采用C/C++编写的软件,在进行移植时,平台无关的的代码基本上不需要做大的改动,但平台相关的代码需要做很大的调整 ...

  8. c++中利用宏定义简化for循环使用

    话不多说,上方法 #define _for(i,a,b) for( int i=(a); i<(b); ++i) #define _rep(i,a,b) for( int i=(a); i< ...

  9. Excel—在Excel中利用宏定义实现MD5对字符串(如:手机号)或者文件加密

    下载宏文件[md5宏] 加载宏 试验md5加密 可能遇到的问题 解决办法 下载宏文件[md5宏] 下载附件,解压,得md5宏.xla md5宏.zip 加载宏 依次打开[文件]-[选项]-[自定义功能 ...

随机推荐

  1. 【MFC学习笔记-作业6-sin图像】【OnDraw(CDC* pDC)】

    根据这段源代码 一步一步剖析CDC的使用 void CDrawSinXView::OnDraw(CDC* pDC) { CDrawSinXDoc* pDoc = GetDocument(); ASSE ...

  2. jps无法获取到tomcat(java)进程

    一.问题描述: Ubuntu 10.10版本,同个JDK 1.6版本,启动tomcat后,使用jps无法获取本机Java进程. 二.jps工作原理: 1. java进程启动时,若没有指定 -Djava ...

  3. 字符串对比.net String.EndsWith方法 (String)

    string str="web/abc.aspx"; if(str.EndsWith("abc.aspx")) { 此方法将 value 与位于此实例末尾.与 ...

  4. Erp第二章:业务流程化、集成、规划

    1从全流程着眼,支持业务流程化优化,通过流程化优化提高工作效率和企业效益 2每个系统业务都相互依存.相互作用. 3.应用 程序(不用厂家)越多,信息集成难度越大 4信息集成.实时共享.实时企业 5信息 ...

  5. 浏览器的重绘(repaints)与重排(reflows)

    转:http://www.css88.com/archives/4991#more-4991 在项目的交互或视觉评审中,前端同学常常会对一些交互效果质疑,提出这样做不好那样做不好.主要原因是这些效果通 ...

  6. for练习--侦察兵

    static void Main21侦察兵(string[] args) { //某侦察队接到一项紧急任务,要求在A.B.C.D.E.F六个队员中尽可能多地挑若干人,但有以下限制条件: //侦察兵A和 ...

  7. Android Studio代码自动提示无效

    不生效的原因是因为你AS设置成了省电模式,设置成省电模式了的话,AS会禁掉一些辅助功能,达到省电的目的.所以代码自动提示也被禁掉了. 要修改回来的话,通过File选项,然后倒数第二项:Power Sa ...

  8. java工厂类与反射机制

    java 简单工厂类 2012-04-22 15:44:07|  分类: java |  标签:java工厂类  简单工厂类  |举报|字号 订阅     简单工厂模式需要由以下角色组成: 接口    ...

  9. 搭建SSH环境之添加所需jar包

    一.首先介绍要添加框架环境: JUnit Struts2 Hibernate Spring (1)配置JUnit /**-------------------------添加JUnit-------- ...

  10. 下拉条的连动-ajax方式

    客户端触发: <select id="category1" onchange="changecategory()">    <option v ...