指针直接赋值为整型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 加载宏 依次打开[文件]-[选项]-[自定义功能 ...
随机推荐
- LeetCode Day3
Lowest Common Ancestor of a Binary Search Tree import java.util.ArrayList; import java.util.List; / ...
- ThreadLocal 在web环境下使用的边界问题
ThreadLocal 相关分析,请查看http://wangxinchun.iteye.com/blog/1884228 另外一个必须要提的点是: ThreadLocal在线程池环境下的使用. 比如 ...
- Revisit-after元标签是什么,SEO的作用是什么
很多网站都使用了revisit-after的问题,关于revisit-after这个标签是什么,revisit-after元标签的作用究竟是什么呢,应该如何使用revisit-after元标签呢? 这 ...
- java调用Command命令
----------- import java.io.BufferedReader; import java.io.InputStreamReader; /** * 此类用来执行Command命令 * ...
- HTML7常用的类型刮刮乐 光棒效果
常用的类型: 1.数学: Math.ceil():天花板数 Math.floor():地板数 Math.round():四舍五入取整数 Math.random():生成0-1之间的随机数 2.日期 ...
- pythonj基础之 多线程
多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进 ...
- UVa 1585 - Score
得分是目前连续O 的个数,遇到X置0 #include <cstdio> #include <iostream> #include <cstring> using ...
- winform制作自定义控件(入门)
原文链接:http://blog.csdn.net/bychentufeiyang/article/details/7081402 与原文基本一致,只是例子变成VS2012环境,语言采用博主常用的 ...
- Linux内核之进程和文件共享
1.Shell命令的执行和进程 Shell 命令可以是内部或者外部命令. 内部(内置)命令(internal (built-in) command)的代码本身就是shell进程的一部分.L ...
- oc @property参数