如何获取结构体某成员的偏移地址
2015-03-31 22:22
239 查看
我们假设结构体定义如下所示:
[cpp] view
plaincopyprint?
#include <stdio.h>
#include <stdlib.h>
struct test_s
{
int pad1;
int pad2;
int pad3;
int pad4;
int pad5;
};
思路1: 非常简单,直接用地址差值即可求得。
[cpp] view
plaincopyprint?
int main(int argc, char *argv[])
{
struct test_s sss;
struct test_s *t = &sss;
printf("%d\n", (int)&(t->pad2));
return 0;
}
思路2: 考虑宏定义的实现。(最佳思路!)
ANSI C标准允许任何值为0的常量被强制转换成任何一种类型的指针,并且转换结果是一个NULL指针,因此( (test_s*)0 )的结果就是一个类型为test_s*的NULL指针。如果利用这个NULL指针来访问s的成员当然是非法的,但&(((test_s*)0)->m)的意图并非想存取test_s字段内容,而仅仅是计算当结构体实例的首址为((s*)0)时m字段的地址。聪明的编译器根本就不生成访问m的代码,而仅仅是根据test_s的内存布局和结构体实例首址在编译期计算这个(常量)地址,这样就完全避免了通过NULL指针访问内存的问题。
[cpp] view
plaincopyprint?
#define OFFSET(Type, member) (size_t)&( ((Type*)0)->member) )
如上做法避免了一定要实例化一个结构体对象,并且求值是在编译期进行,没有运行期负担。因此是该问题的首选方案。
[cpp] view
plaincopyprint?
int main(int argc, char *argv[])
{
size_t offset = OFFSET(test_s, pad4);
return 0
}
实际上这种利用编译器掌握的整个程序的信息以在编译期计算某些值的方法与现在C++编程中很流行的(静态)元编程技术类似,只不过C++程序员可以利用模板技术在编译期完成非常复杂的计算,而缺乏模板支持的 ANSI C在这方面的能力则要弱许多。
C++ 的实现:
[cpp] view
plaincopyprint?
/* Define offsetof macro */
#ifdef __cplusplus
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&reinterpret_cast<const volatile char&>((((s *)0)->m)) )
#else
#define offsetof(s,m) (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))
#endif
#else
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
#endif /* __cplusplus */
[cpp] view
plaincopyprint?
#include <stdio.h>
#include <stdlib.h>
struct test_s
{
int pad1;
int pad2;
int pad3;
int pad4;
int pad5;
};
思路1: 非常简单,直接用地址差值即可求得。
[cpp] view
plaincopyprint?
int main(int argc, char *argv[])
{
struct test_s sss;
struct test_s *t = &sss;
printf("%d\n", (int)&(t->pad2));
return 0;
}
思路2: 考虑宏定义的实现。(最佳思路!)
ANSI C标准允许任何值为0的常量被强制转换成任何一种类型的指针,并且转换结果是一个NULL指针,因此( (test_s*)0 )的结果就是一个类型为test_s*的NULL指针。如果利用这个NULL指针来访问s的成员当然是非法的,但&(((test_s*)0)->m)的意图并非想存取test_s字段内容,而仅仅是计算当结构体实例的首址为((s*)0)时m字段的地址。聪明的编译器根本就不生成访问m的代码,而仅仅是根据test_s的内存布局和结构体实例首址在编译期计算这个(常量)地址,这样就完全避免了通过NULL指针访问内存的问题。
[cpp] view
plaincopyprint?
#define OFFSET(Type, member) (size_t)&( ((Type*)0)->member) )
如上做法避免了一定要实例化一个结构体对象,并且求值是在编译期进行,没有运行期负担。因此是该问题的首选方案。
[cpp] view
plaincopyprint?
int main(int argc, char *argv[])
{
size_t offset = OFFSET(test_s, pad4);
return 0
}
实际上这种利用编译器掌握的整个程序的信息以在编译期计算某些值的方法与现在C++编程中很流行的(静态)元编程技术类似,只不过C++程序员可以利用模板技术在编译期完成非常复杂的计算,而缺乏模板支持的 ANSI C在这方面的能力则要弱许多。
C++ 的实现:
[cpp] view
plaincopyprint?
/* Define offsetof macro */
#ifdef __cplusplus
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&reinterpret_cast<const volatile char&>((((s *)0)->m)) )
#else
#define offsetof(s,m) (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))
#endif
#else
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
#endif /* __cplusplus */
相关文章推荐
- 如何获取结构体某成员的偏移地址
- 如何获取结构体某成员的偏移地址
- 如何通过结构中的某个成员地址获取结构本身的指针???
- 如何求结构体成员的偏移地址 || 结构体的 sizeof 总结
- Oracle 官方文档 结构说明(教你如何快速从官方文档中获取需要的知识)
- 如何取得结构变量的偏移地址
- Oracle官方文档结构说明(教你如何快速从官方文档中获取需要的知识)
- 如何在 Exchange 中获取嵌套组的所有成员
- 如何计算结构体大小和结构体中成员的内存偏移
- 如何用SQL语句获取Oracle表结构
- ANSI C中获取结构体成员偏移量量的办法
- 如何获取数据块结构信息dump
- 如何确定域在结构中的字节偏移量,怎样用结构成员名访问对应成员?
- 如何用SQL语句获取Oracle指定表的表结构
- 通过成员变量地址获取结构体地址
- 通过成员变量地址获取结构体地址
- 获取结构体某成员偏移
- 如何获取SqlServer2005表结构(字段,主键,外键,递增,描述)
- 不实例化结构体获取结构体成员在结构体中的偏移量
- 宏定义求结构体成员偏移地址