[C] How to find a struct through struct elements?

Source: Internet
Author: User

1. Question proposal

We know that if a struct is defined as follows:

 
 
  1. struct _st { 
  2.   int a; 
  3.   char b; 
  4. } st ; 

We can access a or B through st. The method is st. a or if the st pointer pst exists, use pst-> ). However, if you know the element pointer in the struct, can you get the pointer of the current struct? Or, if I can only access B, can I access st and?

2. Practical Significance of this problem

First, what is the purpose of this operation? In fact, I have long known that linus in the Linux kernel uses the container_of () Macro, which is used in this method. Recently, I encountered a problem in the project and thought about a particularly good method. However, using this method can better solve the problem.

In general, the problem is abstracted: There are some blocks that need to be concatenated with multiple linked lists. For example, if there are 5 blocks in B1, B2, B3, B4, and B5, We Need To concatenate them with three linked lists with different functions:

Linked List 1: B1-> B4-> B5

Linked List 2: B2-> B5

Linked List 3: B1-> B2-> B3-> B4-> B5

The project wants to use the linked list library in glib for implementation. Here is an example of a one-way linked list in the linked list library in glib. See the Glib documentation for the Organization ):

 
 
  1. typedef struct { 
  2.   gpointer data; 
  3.   GSList *next; 
  4. } GSList;

Data is linked by a data Pointer to implement a one-way linked list. Here, if someone has a recommended library, I 'd like to talk about it. Here, if we use the glib library, it is obviously not easy to implement the functions we want, because we do not know whether B2's next is to point to B5, such as linked list 2) or B3, such as linked list 3 ). We obviously need multiple next pointers to achieve this. If we use the following method:

 
 
  1. struct _block { 
  2.   int data; 
  3.   GSlist list1; 
  4.   GSlist list2; 
  5.   GSlist list3; 
  6. }; 

Because the next pointer of each GSlist is directed to the list1 or list2/3 element of the next block, it is difficult to obtain the data of the data Field. At this time, you need to find data through the list1 pointer. This is the question we raised.

3. Consider

You can find out how the struct exists in the memory. For example:

In this way, we can use addition and subtraction to calculate the address of the struct of the integer a pointed to by pa. The compiler certainly knows all of the above, but how can we reflect it in code?

In fact, we don't need to know the problem above to express it in code. You can see the following method section.

4. container_of () Analysis

Since we know that in the Linux kernel, linus uses a tricky macro such as container_of () to obtain the pointer of the current struct through the pointer of elements in a struct. Here, you can use it directly.

The implementation method of container_of () is very simple and clever. Its core is two macro definitions:

 
 
  1. #ifndef offsetof 
  2. #define offsetof(type, field)   ((long) &((type *)0)->field) 
  3. #endif   /* offsetof */ 
  4.  
  5. #ifndef container_of 
  6. #define container_of(ptr, type, member) ({          \ 
  7.     const typeof( ((type *)0)->member ) *__mptr = (ptr);    \ 
  8.     (type *)( (char *)__mptr - offsetof(type,member) );}) 
  9. #endif 

There are three major macros: typeof (), offsetof (), and container_of (). Let me talk about some of my understandings:

 
 
  1. int main(void) 
  2.     printf("%d.\n", (1,2,3)); 
  3.     printf("%d.\n", ({int i=1,j;j=i+2;})); 
  4.     return 0; 
5. container_of () Example

Here is a simple example of using container_of:

 
 
  1. /*
  2. * desc : a simple example to use container_of() macro
  3. * mail : xzpeter@gmail.com
  4. */
  5. #include <stdio.h> 
  6.  
  7. #ifndef offsetof 
  8. #define offsetof(type, field)   ((long) &((type *)0)->field) 
  9. #endif   /* offsetof */ 
  10.  
  11. #ifndef container_of 
  12. #define container_of(ptr, type, member) ({          \ 
  13.     const typeof( ((type *)0)->member ) *__mptr = (ptr);    \ 
  14.     (type *)( (char *)__mptr - offsetof(type,member) );}) 
  15. #endif 
  16.  
  17. typedef struct _A { 
  18.     int a; 
  19.     char b; 
  20.     long long c; 
  21.     double d; 
  22. } SA ; 
  23.  
  24. SA sa = { 
  25.     .a = 10, 
  26.     .b = 'c', 
  27.     .c = 204, 
  28.     .d = 3.14, 
  29. }; 
  30.  
  31. int main(int argc,char *argv[]) 
  32.     double *pd = &sa.d; 
  33.     /* now we have a pointer pd -> sa.d, let's access element c with pd */ 
  34.     printf("SA.c = %lld\n", container_of(pd, SA, d)->c); 
  35.     return 0; 

Here, I have defined a structure sa and obtained the sa. c value through the sa. d pointer. The output is:

 
 
  1. SA.c = 204 

In this way, we can also get block. data through block. next.

References:

This article is from the LoudMouth Peter blog, please be sure to keep this source http://xzpeter.blog.51cto.com/783279/339497

Related Article

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.