-1

I transplanted a doubly linked list from the linux kernel, but I found some problems when testing the inserted elements of the linked list,the test code is as follows.when i run the test case,i find the result is so weirdenter image description here.However I put the stu_list member at the beginning of struct student,the result is normalenter image description here.Please tell me why there is such a result and the principle,thanks!

struct list_head {
    struct list_head *next, *prev;
};
struct student {
    int id;
    int grades;
    struct list_head stu_list;
};

int main(void) {
    struct student stu1, stu2;
    struct student *p;
    struct list_head *pos;

    INIT_LIST_HEAD(&stu1.stu_list);
    INIT_LIST_HEAD(&stu2.stu_list);

    for (volatile int i = 0; i < 6; i++) {
        p = (struct student *) malloc(sizeof(struct student));
        p->id = i;
        p->grades = 90 + i;
        list_add_tail(&p->stu_list, &stu1.stu_list);
    }
    printf("list add result:\n");
    list_for_each(pos, &stu1.stu_list) {
        printf("ID = %d,grades = %d\n", ((struct student *) pos)->id, ((struct student *) pos)->grades);
    }
    return 0;
}
linuxer
  • 21
  • 2
  • 2
    Please don't try to show images of text. Copy-paste text *as text* into your questions. Also please take some time to lead read [the help pages](http://stackoverflow.com/help), take the SO [tour], read [ask], as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Oct 19 '21 at 08:44
  • 1
    Off topic but... the use of the `volatile` keyword is completely redundant here. – G.M. Oct 19 '21 at 08:46
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Oct 19 '21 at 08:54

1 Answers1

2

The problem is (struct student *) pos).

The C standard allows to convert a pointer to a struct to a pointer of its first member. Therefore the code works only if the stu_list is the first member of the parent struct.

Otherwise, you should use container_of-like macro to transform a pointer to struct list_head to the embedding structure which is struct student.

Please read container_of post or other post for more information.

To fix the issue add the following macro:

#define list_entry(ptr,type,member) \ 
         ((type*)(((char*)ptr) - offsetof(type,member))) 

Now the body of printing loop should be:

list_for_each(pos, &stu1.stu_list) {
        struct student *s = list_entry(pos, struct student, stu_list);
        printf("ID = %d,grades = %d\n", s->id, s->grades);
}
tstanisl
  • 13,520
  • 2
  • 25
  • 40