编译器在为结构体成员分配内存时,由于存在内存对齐机制,各个成员所占空间可能不是连续的,因而不能简单的通过成员类型所占的字长来推断其它成员或结构体对象的地址。
获得结构体成员偏移量的方法可以参照博客:
/zhanshen/article/details/51500757
现在主要以第二种方法(通过宏函数计算结构体成员偏移量)为例,做简单整理和介绍
(注:typeof还没有写进C++标准,只是gcc里面的,但C++引入了decltype和auto关键字,如果是用C++编写的代码,则可以用decltype(c++ 11)替代typeof)
如果你仅仅是想根据初始化值为一个变量推断合适的数据类型,那么使用auto是一个更加简单的选择。当你只有需要推断某个表达式的数据类型,例如某个函数调用表达式的计算结果的数据类型,而不是某个变量的数据类型时,你才真正需要delctype。具体可以参考博客:
/fjb2080/article/details/7527244
gcc编译:
#include <stdio.h>#define GET_OFFSET(data,member) (size_t)(&(((typeof(data)*)0)->member))typedef struct student{int a;char ch[2];double d;}student_t;int main(int argc, char const *argv[]){student_t stu ;int offset ;offset= GET_OFFSET(stu, d);printf("%d\n",offset );return 0;}
代码分析如下:
1. typeof 关键字:
用于获取修饰修饰变量的数据类型。比如 int value; typeof( value ) 的作用是获得 value 的数据类型int 。
用法:
int value; 我想要定义一个 和value这个变量类型一样的新变量new_value ;
操作像这样: typeof(value) new_value ;
该用法可以用在函数的值传递中,在不知道值的类型的时候,可以定义和它类型相同的新变量。
2. typedef :
为数据类型起一个名字 :比如 typedef struct student student_t ;
约定 :一般新名字后面以 _t 结尾,表示是一个构造出来的新类型名字,便于理解。
student_t stud1 ; 等价于 struct student stud1 ; 很显然 前者更有利于移植和阅读。
3. ((data_type)0)
作用:把数字 0 强制转换成 (data_type) 类型的指针。
比如:( struct student * )0 的作用是把 0 转换成 struct student类型的指针,用于引用struct student数据类型类型的成员。
在这个题目中: ((typeof(data)*)0)->member 的目的是 把 0 转成 data 变量对应的数据类型的指针,然后通过该指针引用该类型的成员的值。
对于本题而言: (size_t)(&(((struct student *)0)->d)) : & 用以获取struct student结构的成员d ,然后,获得d 的地址,将它转成 size_t 的数据类型量。
其中 size_t 的定义是 typedef unsigned int size_t ;
(size_t)(&(((struct student *)0)->d)) 它的值是变量d的地址,为什么是偏移值呢? 因为 起始地址我们认为规定为 0。
4. size_t :
typedef unsigned int size_t ;
原文:/baidu_33725271/article/details/69323694
C++编译:
#include<iostream>using namespace std;#define GET_OFFSET(data,member) (size_t)(&(((decltype(data)*)0)->member))struct student{int a;char ch[2];double d;};int main(int argc, char const *argv[]){struct student stu;int offset;offset = GET_OFFSET(stu, d);cout << offset << endl;return 0;}