指针直接赋值为整型AND利用宏定义求结构体成员偏移量
首先我们要更正一个很熟悉的概念,那就是指针不仅仅是“地址”,指针还有一个很重要的特性,那就是“类型”。
指针初始化时,“=”的右操作数必须为内存中数据的地址,不可以是变量,也不可以直接用整型地址值(但是 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利用宏定义求结构体成员偏移量的更多相关文章
- go语言基础之结构体成员的使用指针变量
1.结构体成员的使用:指针变量 示例: package main //必须有个main包 import "fmt" //定义一个结构体类型 type Student struct ...
- go 结构体定义和结构体指针
结构体一个结构体(`struct`)就是一个字段的集合. 将来要使用它向java .C# 中的class 有相同的地位 struct 可以用来值传递 同时可以通过引用传递参数(地址) java C# ...
- iOS下单例模式实现(二)利用宏定义快速实现
在上一节里提到了用利用gcd快速实现单例模式. 一个项目里面可能有好几个类都需要实现单例模式.为了更高效的编码,可以利用c语言中宏定义来实现. 新建一个Singleton.h的头文件. // @int ...
- swap 用指针交换两个整型数值
- [GO]结构体成员的使用:指针变量
package main import "fmt" func main() { type student struct { id int name string sex byte ...
- 利用宏定义令iOS项目当中的NSLog不执行
今天在博客园主页看到一篇帖子,提到NSLog消耗运行时性能: http://www.cnblogs.com/sunnyxx/p/3680623.html 解决方案如下,在Prefix.pch文件当中 ...
- 利用宏定义实现C++程序在Unix和Win32环境下的通用性
[转] 1.1. 宏定义软件的代码,从跨平台的角度来看,可以分为平台相关的和平台无关的.采用C/C++编写的软件,在进行移植时,平台无关的的代码基本上不需要做大的改动,但平台相关的代码需要做很大的调整 ...
- c++中利用宏定义简化for循环使用
话不多说,上方法 #define _for(i,a,b) for( int i=(a); i<(b); ++i) #define _rep(i,a,b) for( int i=(a); i< ...
- Excel—在Excel中利用宏定义实现MD5对字符串(如:手机号)或者文件加密
下载宏文件[md5宏] 加载宏 试验md5加密 可能遇到的问题 解决办法 下载宏文件[md5宏] 下载附件,解压,得md5宏.xla md5宏.zip 加载宏 依次打开[文件]-[选项]-[自定义功能 ...
随机推荐
- C++ 顶层 const
我的主力博客:半亩方塘 本文的主要參考来源来自于:C++ Primer 中文版(第 5 版) 第 57 面至第 58 面 1. 顶层 const 与底层 const 概念 我们知道,指针本身是一个对象 ...
- C# in Depth阅读笔记1:C#1特性
1.委托 委托是对包含返回值和参数的行为的一种封装,类似于单一方法的接口. 委托是不易变的(就像string),system.delegate下的combine和remove方法都只能产生一个新的委托 ...
- <!--转换office时需要此配置 --> <identity impersonate="true" />
1.需要对Office 进行操作时 ,添加权限 <!--转换office时需要此配置 --> <identity impersonate="true" /> ...
- timeout Timeout时间已到.在操作完成之前超时时间已过或服务器未响应
Timeout时间已到.在操作完成之前超时时间已过或服务器未响应 问题 在使用asp.net开发的应用程序查询数据的时候,遇到页面请求时间过长且返回"Timeout时间已到.在操作完成之间超 ...
- NOPI 导出excel 通用方法
public static byte[] ExportExcel<T>(Dictionary<string, string> columnsHeader, List<T& ...
- iOS开发之网络请求(基于AFNetworking的再封装)
最近一直很忙也没有什么时间写博客了.放假了休息一下,就写一篇博客来总结一下最近做项目中出现过的问题吧!!! 首先,在项目中我的起到了什么作用,无非就是把美工(UI设计师)给我们的图显示出来,然后再和服 ...
- 设计模式之UML类图
在学设计模式的过程中经常碰到各式各样的UML类图.那些眼花缭乱的符号有什么含义呢? 类图含义 类图中的关系 从网上找来一张图作为实例 依赖关系:比如动物依赖氧气和水,这里如学生要依赖自行车.用虚线箭头 ...
- 浏览器文档播放Shockwave Flash 插件问题
浏览器被提示shockwave flash crashed怎么办?在使用浏览器的时候经常被提示shockwave flash crashed,flash插件崩溃,网页就会出现一些无法显示的文件,下面绿 ...
- Spring发送电子邮件
Spring提供了发送电子邮件的功能,它向用户屏蔽了底层邮件系统的一些细节,同时代表客户端负责底层的资源处理. Spring的邮件服务支持主要是通过JavaMailSender这个接口实现的: p ...
- jquery append 动态添加的元素事件on 不起作用的解决方案
用jquery添加新元素很容易,面对jquery append 动态添加的元素事件on 不起作用我们该如何解决呢?on方法中要先找到原选择器(如例.info),再找到动态添加的选择器(如列.delet ...