My detailed explanation of the containing_record macro

Source: Internet
Author: User

Macro containing_record is very useful and convenient. Its main functions are as follows:
Calculate the pointer of a struct Based on the pointer of a member!
Let's start with a simple example:
We define a struct with the following types:

typedef struct{    int a;    int b;    int c;}ss;

This is a very simple struct. There is nothing special about it. Perform a slight analysis on this struct:
Struct size (in bytes): 4 + 4 + 4 = 12 bytes
Offset of member A: 0
Offset of member B: 4
Offset of member C: 8
We use ss to define a variable:
Ss s = {1, 2, 3 };
Then the values of A, B, and C are respectively: a = 1, B = 2, c = 3.
In fact, the compiler assigns values to member variables when generating code:
If the address of S is: 0x12000000, then:
* (Int *) (char *) & S + 0) = 1;
* (Int *) (char *) & S + 4) = 2;
* (Int *) (char *) & S + 8) = 3;
That is to say, the variable offset is added on the basis of the & S address to determine the member pointer and assign a value. Therefore:
& S-> A will get 0x12000000 + 0 = 0x12000000
& S-> B will get 0x12000000 + 4 = 0x12000004
& S-> C will get 0x12000000 + 8 = 0x12000008
So: structure address + member variable offset = member variable address
Move the following item: Address of the member variable-offset of the member variable = address of the Structure
Wow, this is the address we want, not a subtraction ~~~ Bytes

First, we know the address of the member variable.
Second, we need to get the offset of the member variable (assuming the offset of member B ).
What should we do? We can do this:
& S-> B-(unsigned long) & S, so that the offset of member B can be obtained. However, & S is what we need, and it is obviously unknown for the time being, in this case...
So, let's perform subtraction again (incorrect C language expression, but the result is okay. Here it just seems clear ):
& (S-S)-> B-(unsinged long) & (s-s ),
To ensure consistency of types, you must:
S-s = (SS *) 0
(Unsigned long) & (S-S) = (unsigned long) (SS *) 0 = 0. simply omit this part.
Then, the simplification result is: & (SS *) 0)-> B-(unsigned long) 0
The simplest result is: & (SS *) 0)-> B, which is the offset of B.
Haha, it's easy. It's just a wonderful use of the 0 pointer. It's only two subtraction operations in total ~ It is certainly not a problem for your math emperor ~
Among them, we need to know the prototype of the SS struct, which is a member variable B in the SS struct (in fact, both are the same, but must be consistent with the variable that provides the pointer)

To sum up, we need to provide the address of a member variable in the struct, the prototype of the struct, and a member variable in the struct (which is the same as the previous variable)

The final containing_record is defined:

# Define containing_record (ADDR, type, field) (type *) (unsigned char *) ADDR-(unsigned long) & (type *) 0)-> Field ))
ADDR: the address of a member variable in the struct.
Type: struct prototype
Field: a member of the struct (same as the previous one)

All the conclusions come out. This is the 10 thousand formula. No matter which result of the member variable is correct, this is relative to knowing the address of the first variable:
If you know the address of the first Member (Pa = & S-> A), this is the simplest case:
Directly force type conversion: (SS *) Pa. At this time, & (type *) 0)-> field is exactly 0.
Therefore, the result is (type *) ADDR. The simplest case is also the one we are most likely to think of, for example, placing the linked list element at the beginning of the struct ~~~
  
Now the containing_record macro is finished ~
Now, when using two-way linked lists such as list_entry, you can use the containing_record macro to obtain the address of the entire struct In the traversal Link Table no matter where the linked list is placed ~
Remember to free the entire struct address when removing an element from the linked list. The operation function provided by wdk only disconnects the linked list element from the entire linked list ~~~

BTW:
The reason for converting ADDR to unsigned char * is that the unit of calculation in Pointer calculation is 1, that is, (unsigned char *) ADDR + 1 = ADDR + 1, if it is not converted, it is definitely incorrect.
Convert & (type *) 0)-> field to (unsigned long) Four byte widths, and ensure that the expression is not composed of two pointer arithmetic operations, because the C language standard does not define such an operation

I have written so much, so I hope I can't do anything ~
Girl don't cry (QQ: 191035066) @ 18:56:57 http://www.cnblogs.com/nbsofer

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.