分类: C/C++
2009-10-16 10:59:52
#define 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,所以这个地址的值就是字段相对于结构体基址的偏移。
如上做法避免了一定要实例化一个MyStruct对象,并且求值是在编译期进行,没有运行期负担。实际上这种利用编译器掌握的整个程序的信息以在编译期计 算某些值的方法与现在C++编程中很流行的(静态)元编程技术类似,只不过C++程序员可以利用模板技术在编译期完成非常复杂的计算,而缺乏模板支持的 ANSI C在这方面的能力则要弱许多。
C++中已经提供了可用的宏:offsetof(type,field)来计算这个filed在type中的偏移,但是需要include stddef.h头文件