当前位置:网站首页>Offsetof macro and container_ Of macro analysis details
Offsetof macro and container_ Of macro analysis details
2022-07-28 11:04:00 【tutu-hu】
One . summary
offsetof Macro and container_of Macro in linux Kernel has a very wide range of applications . These two macros also have very powerful functions , among offsetof Macro is used to obtain the offset of a variable of the structure relative to the first address of the structure ;container_of Macro is used to deduce the first address of structure variable according to the address of structure member variable . In addition, it is also meaningful to analyze the implementation process of these two macros , It can help us understand C The operation of language on memory . Next, we will analyze its implementation process with specific code .
Two .offsetof macro
<1>offset The function of a macro is : It is used to calculate the offset between an element in the structure and the first address of the structure ( Its essence is to help us calculate through the compiler ).
<2>offset Macro principle : We have a virtual one type Type structure variable , And then use type.member To visit that member Elements , And then we get member The offset from the first address of the entire variable .
<3>offset Macro expression :
// Use offset Macro gets the offset address of the structure variable , among :TYPE Represents the structure type name ,MEMBER Represents the member variable name
#define offsetof(TYPE,MEMBER) ((int)&((TYPE *)0)->MEMBER)
1. Sample code :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// Use offsetof Macro gets the offset address of the structure variable , among :TYPE Indicates the structure name ,MEMBER Represents the member variable name
#define offsetof(TYPE,MEMBER) ((int)&((TYPE *)0)->MEMBER)
//64 Bit operating system , Default 8 Byte alignment
struct student
{
char a; //8(4+4)
double b; //8
int c; //8(4+4)
};
int main(int argc,char *argv[])
{
struct student stu1 = {
0};
stu1.b = 11.22;
printf("&stu1 = %p\n",&stu1); // Structure start address
printf("&stu1.a = %p\n",&stu1.a); // member a The address of
printf("&stu1.b = %p\n",&stu1.b); // member b The address of
printf("&stu1.c = %p\n",&stu1.c); // member c The address of
int offset_a = offsetof(struct student,a); // Get member variables a The offset address of
int offset_b = offsetof(struct student,b); // Get member variables b The offset address of
int offset_c = offsetof(struct student,c); // Get member variables c The offset address of
printf("offset_a = %d\n",offset_a);
printf("offset_b = %d\n",offset_b);
printf("offset_c = %d\n",offset_c);
printf("stu1.b = %lf\n",*(double*)((char*)&stu1 + offsetof(struct student,b)));
return 0;
}
2. Result display
Because in linux Environment implementation , The computer is 64 Bit operating system , Default 8 Byte alignment , So member variables a,b,c The address offsets of are 0,8,16. Combined with theoretical analysis, the actual program execution results are as follows :
&stu1 = 0x7ffd4d101490
&stu1.a = 0x7ffd4d101490
&stu1.b = 0x7ffd4d101498
&stu1.c = 0x7ffd4d1014a0
offset_a = 0
offset_b = 8
offset_c = 16
stu1.b = 11.220000
Found not , It is the same as the result of our analysis !
3.offsetof Macro implementation principle analysis
Let's try to analyze ((int)&((TYPE *)0)->MEMBER):
(1)(TYPE *)0 ----------------> (struct student *)0
This is a cast , hold 0 The address coercion type is converted to a pointer , This pointer points to a TYPE Structure variable of type . In fact, this structure variable may not exist , But as long as we don't dereference this pointer, there will be no error . The actual meaning is that we force 0 This address uses TYPE The structure type of type explains . Whether he exists or not , As for why 0 Address ? It is to find the offset address of other member variables more conveniently .
(2)((TYPE *)0)->MEMBER ----------------> ((struct student *)0)->a
In fact, it refers to the member variable through the structure pointer
(3)&((TYPE *)0)->MEMBER ----------------> &(((TYPE *)0)->MEMBER) ----------------> &(((struct student *)0)->a)
The explanation of this sentence should be to obtain the structural variable first , Then take the address of this variable . What you naturally get is the actual address of the structural variable , The modified structure is forcibly placed in 0 address , Therefore, the address of the obtained member variable is the cheap address of the variable . Finally using int Force type conversion .
3、 ... and .container_of macro
<1>container_of The function of a macro is : The first address of the structure variable is derived from the address of the structure member variable .
<2>offset Macro principle : In a word, the address of the current variable minus the offset of the variable ( You can use the above offsetof Macro calculation ) Is the first address of the structure variable .
<3>offset Macro expression :
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
1. Sample code :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//<1>offsetof Use of macros
//offset The function of a macro is : Use a macro to calculate the offset between an element in a structure and the first address of the structure ( Its essence is to help us calculate through the compiler ).
// among :TYPE Indicates the structure name ,MEMBER Represents the member variable name
#define offsetof(TYPE,MEMBER) ((int)&((TYPE *)0)->MEMBER)
//<2>container_of Use of macros
// Use container_of The macro is based on the address of the structure member variable , Get the address of the structure variable
// among :ptr It refers to structural elements member The pointer to ,type Is the structure type ,member Is the element name of an element in the structure
// This macro returns a pointer to the entire structure variable , The type is (type *)
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
struct student
{
char a; //8(4+4)
double b; //8
int c; //8(4+4)
};
int main(int argc,char *argv[])
{
struct student stu1 = {
0}; // Define structure variables stu1
struct student *getstu; // Used to receive the obtained structure variable address
getstu = container_of(&stu1.b,struct student,b); // According to the member variable b Get the address of the structure variable and return
printf("getstu = %p\n",getstu); // Print the obtained address
printf("&stu1 = %p\n",&stu1); // Print the actual address
return 0;
}
2. Result display
Calculate the first address of the structure variable and compare it with the original actual address , It can be seen that the calculated address is completely correct !
getstu = 0x7ffce5ec4270
&stu1 = 0x7ffce5ec4270
3.container_of Macro implementation principle analysis
It can be seen that container_of The macro is divided into two pointing statements , The first sentence :const typeof( ((type *)0)->member ) *__mptr = (ptr); The role of is : use first typeof Get the type of the member variable , Then use this type to define a pointer variable __mptr And the address of the member variable ptr Assign to __mptr. such __mptr What's kept in this book is ptr Value .
The second sentence is :(type *)( (char *)__mptr - offsetof(type,member) );}) In fact, it is to use the above offsetof The macro calculates the offset address of the member variable relative to the first address of the structure variable , Then the current address - offset = Structure variable first address . It's a very simple data calculation , A little difficult is right C Understanding of language memory operation and variable type conversion .
边栏推荐
- FHWY工作日进度表
- GKRidgedNoiseSource
- Yan reports an error: exception message: /bin/bash: line 0: fg: no job control
- GKConstantNoiseSource
- Build a quick development ide: visualsvn + sublime + Visual Studio 2013 + quickeasyftpserver
- The 10th Landbridge cup embedded electronic provincial competition
- GKCheckerboardNoiseSource
- Configuring raspberry pie, process and problems encountered
- Question of hanging the interviewer
- GKVoronoiNoiseSource
猜你喜欢

Pyqt5 rapid development and practice 4.13 menu bar, toolbar and status bar and 4.14 qprinter

Sword finger offer 35. replication of complex linked list

Why is low code (apaas) popular again recently?

Relevant knowledge points of hash table

I don't know how lucky the boy who randomly typed logs is. There must be a lot of overtime

蓝桥杯嵌入式-HAL库-USART_TX

GKSpheresNoiseSource

Semeval 2022 | introducing knowledge into ner system, aridamo academy won the best paper award

5. Implement MapReduce program on window side to complete wordcount function

Reading these six books makes learning MySQL easier
随机推荐
The blogs of excellent programmers at home and abroad are all here, please check it
蓝桥杯嵌入式-HAL库-LCD
Select without the order by clause, the order of the returned results is not reliable
BOM部分属性及理解
MySQL Architecture Principle
Semeval 2022 | introducing knowledge into ner system, aridamo academy won the best paper award
Yan reported an error: could not find any valid local directory for nmprivate/
Development environment configuration of nodemcu
低代码(aPaas)为什么最近又火了?
Samba learning
几个数据库的相关概念
Sword finger offer 06. print linked list from end to end
Redis-day01 common sense supplement and redis introduction
GKVoronoiNoiseSource
Invalid ROM Table原因及解决办法
nodemcu之开发环境配置
EC20/EC25 4G模块AT指令开发总结
Eslint, eslint Chinese document
蓝桥杯嵌入式-HAL库-ADC
Cortex-M内核管理全局中断的三种方式