当前位置:网站首页>自动获取结构体内部成员变量的位置偏移
自动获取结构体内部成员变量的位置偏移
2022-06-12 23:04:00 【执假以为真】
提一个问题:已知一个结构体的名称和该结构体内的一个成员变量的名称,如何得到该成员变量在该结构体内的位置偏移?
举个C语言结构体的例子:
typedef struct _node {
int value32;
long value64;
struct _node * next;
} Node;
如上所示,如何得知 next在 Node中的位置偏移?
像这样一个简单的结构体自然可以人工计算一下即可。但如果是一个比较宏大的结构体,有数十上百个成员变量,要想知道中间某个变量的相对位置偏移,就比较麻烦了。
即使数得出来,将来也可能在其之前增加一些其他成员变量,到时候,这个数出来的值就失效了,又要重新数。
所以,如果用程序去计算指定成员变量的偏移,应该怎么做呢?
用下面的一行代码就可以做到。
#define GET_OFFSET(_type, _member) ((unsigned long)(&((_type *)0)->_member))
解释一下:
将地址0当作是一个Node实例的地址,从而自然可以使用->next获得next成员变量,再用取地址符就取得了next成员变量的地址。
因为该实例本身的地址从0开始,那么此处取到的next成员变量的地址自然就是位置偏移了。
那么为什么这个值不是负数呢?
笔者猜想,这是因为编译器假设这个实例在堆中,而在程序的进程空间中,堆地址是自低地址向高地址增长的,因此就是正数了。又或者根本也没那么复杂,编译器就只是简单认为成员变量的地址相对该实例的起始地址是逐渐增长的,而不是逐渐递减的。
完整的程序代码如下:
#include <stdio.h>
#define GET_OFFSET(_type, _member) ((unsigned long)(&((_type *)0)->_member))
typedef struct _node {
int value32;
long value64;
struct _node * next;
} Node;
int main()
{
unsigned long offset = GET_OFFSET(Node, next);
printf("offset of next = %ld\n", offset);
return 0;
}
上述程序的执行结果为:
offset of next = 16
这个方法对C++的类也适用,但是只能对public类型的成员变量计算位置偏移,如下:
#include <iostream>
using namespace std;
#ifdef __cplusplus
#define ENV "CPP"
#else
#define ENV "C"
#endif
#define GET_OFFSET(_type, _member) ((unsigned long)(&((_type *)0)->_member))
class Node {
public:
virtual int getValue32() {
return value32; }
virtual int getValue64() {
return value64; }
Node(int v32=0, int v64=0) : value32(v32), value64(v64) {
}
private:
int value32;
long value64;
public:
Node * next;
};
int main()
{
unsigned long offset = GET_OFFSET(Node, next);
unsigned long offset_in_c_way = (unsigned long)(&((Node *)0)->next);
cout << "ENV=" << ENV <<endl;
cout << "offset of next = " << offset << endl;
return 0;
}
执行结果为:
ENV=CPP
offset of next = 24
这里的offset之所以变成了24而不是16,是因为在Node实例的顶部有一个虚表指针,占用了8个字节,因此next成员变量的位置偏移从16字节变成了24字节。
另一个问题来了,我们计算成员变量在结构体内部的偏移有什么用呢?
这个请看下回分解。
(完)
边栏推荐
- Alcohol detector based on 51 single chip microcomputer
- LeetCode —— 26. Remove duplicates from an ordered array
- DETR(Detection with Transformers) 学习笔记
- Zhengzhou University of light industry -- development and sharing of harmonyos pet health system
- Analysis report on production and marketing demand and investment forecast of China's Melamine Industry from 2022 to 2028
- Report on the "fourteenth five year plan" and strategic strategy recommendations for China's intellectual property protection industry 2022 ~ 2028
- C language: how to give an alias to a global variable?
- Colab tutorial (super detailed version) and colab pro/colab pro+ usage evaluation
- LeetCode 890 查找和替换模式[map] HERODING的LeetCode之路
- [Part 8] semaphore source code analysis and application details [key points]
猜你喜欢

【建议收藏】通俗易懂图解网络知识-第一篇

Summary of MySQL foundation view

MySQL基础篇视图的总结

Photoshop:ps how to enlarge a picture without blurring
![Leetcode 890 finding and replacing patterns [map] the leetcode path of heroding](/img/a2/186439a6d50339ca7f299a46633345.png)
Leetcode 890 finding and replacing patterns [map] the leetcode path of heroding

The carrying capacity of L2 level ADAS increased by more than 60% year-on-year in January, and domestic suppliers "emerged"

MySQL case when then function use

Model over fitting - solution (II): dropout

Colab tutorial (super detailed version) and colab pro/colab pro+ usage evaluation

Insight into China's smart medical industry in 2022
随机推荐
Theory + practice will help you master the dynamic programming method
Analysis report on investment and development trend of gap base of Chinese traditional medicine 2022 ~ 2028
ShardingSphere-proxy-5.0.0部署之分表实现(一)
Research Report on market supply and demand and strategy of tizanidine industry in China
QT quick 3D learning: mouse picking up objects
Insight into China's smart medical industry in 2022
The carrying capacity of L2 level ADAS increased by more than 60% year-on-year in January, and domestic suppliers "emerged"
Mysql concat_ WS, concat function use
MYSQL 行转列、列转行、多列转一行、一行转多列
人脸检测:MTCNN
Mysql concat_ws、concat函数使用
Is it safe to open an account in tonghuashun? How to open an account for securities
C language: how to give an alias to a global variable?
Gb28181 protocol -- alarm
Go时间格式化 赋值
【LeetCode】数组中第K大的元素
ShardingSphere-proxy-5.0.0部署之分表实现(一)
Is it safe to open an account in flush? How to open an account online to buy stocks
四元数简介
Avoid using asp Net core 3.0 to inject services for startup classes