posts - 66,comments - 159,trackbacks - 0
这个是不小心被我撞见的,看到#define宏定义比较特别,仔细看了一下,发现原来有如此作用(请不要怪我少见多怪哦)。
自己编写一小程序试之,贴出代码与运行结果与大家共享。

代码:
#include <stdio.h>
 
#define PACKVALUE 4
#pragma pack(push)
#pragma pack(PACKVALUE)        
typedef 
struct
{
        
char sa;
        
double sb;
        
int sc;
} innerS;
 
typedef 
struct
{
        
int a;
        
char b;
        
short c;
        innerS d[
2];
} testS;
 
#pragma pack(pop)
 
typedef unsigned 
long dword;
 
#define FSIZE(type, field) sizeof(((type*)0)->field)
#define FPOS(type, field) ((dword) & ((type*)0)->field)
 
int main(void)
{
        printf(
"#pragma pack(%d):\nsizeof(char)=%d; sizeof(short)=%d; sizeof(int)=%d; sizeof(double)=%d\n\n",
                        PACKVALUE, 
sizeof(char), sizeof(short), sizeof(int), sizeof(double));
 
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, a), FPOS(testS, a));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, b), FPOS(testS, b));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, c), FPOS(testS, c));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d), FPOS(testS, d));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d[0]), FPOS(testS, d[0]));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d[0].sa), FPOS(testS, d[0].sa));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d[0].sb), FPOS(testS, d[0].sb));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d[0].sc), FPOS(testS, d[0].sc));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d[1]), FPOS(testS, d[1]));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d[1].sa), FPOS(testS, d[1].sa));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d[1].sb), FPOS(testS, d[1].sb));
        printf(
"FSIZE = %d, FPOS = %d\n", FSIZE(testS, d[1].sc), FPOS(testS, d[1].sc));
        
return 0;
}


运行结果:

看来这是一个很不错的用来研究结构体对齐问题的辅助工具,比我上一次自己编写的那个查看内存的函数好用很多。


不过对于#define FPOS(type,field) ((dword) & ((type*) 0)->field)是如何实现的还是不懂,还望高人指点。  

posted on 2008-05-06 17:33 shosh 阅读(236) 评论(4)  编辑 收藏 引用 所属分类: 程序设计

FeedBack:
# re: 查看结构体成员的大小和偏移地址的方法
2008-05-06 21:23 | xu
#define FPOS(type,field) ((dword) & ((type*) 0)->field)是如何实现的可以看一下linux操作系统,里面有很多这样的用法。主要原理是编译器较智能,它会创建一个type类型的支持,地址为NULL(0)。一般求偏移的&(A->a)-&A的方法但A的地址为0是就是那样了。  回复  更多评论
  
# re: 查看结构体成员的大小和偏移地址的方法
2008-05-06 21:26 | xu
它会创建一个type类型的指针,更加详细可以看:
http://blog.csdn.net/chief1985/archive/2008/03/29/2229486.aspx  回复  更多评论
  
# re: 查看结构体成员的地址偏移量
2008-05-07 08:24 | shosh
Re: Xu
谢谢你的回复。
------------------------

终于明白了FPOS的定义的意思了。昨天一直把&当成是与操作,可是dword是类型,类型怎么也可以与操作的,是不是学习的盲点?原来&不是与运算符,而是取地址符。这样就不难理解上面那句定义了。dword只是强制类型转化,因为取地址符得到的地址编号。这里假想在0这个地址存在有type这个类型的结构体,然后对这个结构体的field成员取地址,因为这个结构体是从0地址开始的,所以成员本身的地址就是相对于这个结构体的偏移量。

不过上午看了xu的回复中的那个链接地址:http://blog.csdn.net/chief1985/archive/2008/03/29/2229486.aspx,里面有一段话讲得很精辟,故引用之:
--------------------------------
#define MY_OFFSET (size_t)&(((MyStruct*)0)->MyField)
  上面定义的MY_OFFSET宏就是我们要的MyField的偏移。一定有人问,这样强制转换后的结构指针怎么可以用来访问结构体字段?呵呵,其实这个表达式根本没有也不打算访问MyField字段。ANSI C标准允许任何值为0的常量被强制转换成任何一种类型的指针,并且转换结果是一个NULL指针,因此((MyStruct*)0)的结果就是一个类型为MyStruct*的NULL指针。如果利用这个NULL指针来访问MyStruct的成员当然是非法的,但&(((MyStruct*)0)->MyField)的意图并非想存取MyField字段内容,而仅仅是计算当结构体实例的首址为((MyStruct*)0)时MyField字段的地址。聪明的编译器根本就不生成访问MyField的代码,而仅仅是根据MyStruct的内存布局和结构体实例首址在编译期计算这个(常量)地址,这样就完全避免了通过NULL指针访问内存的问题。又因为首址的值为0,所以这个地址的值就是字段相对于结构体基址的偏移。  回复  更多评论
  
# re: 查看结构体成员的大小和偏移地址的方法
2008-05-24 19:12 | wanderer
受益了,谢谢!  回复  更多评论
  

Copyright ©2007 shosh
Powered By博客园 模板提供:沪江博客 修改:shosh