Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Забавный макрос container_of


Автор: newbie2009 16.8.2013, 04:05
Доброго времени суток.

Наткнулся на такую вот статью - http://linuxkernel51.blogspot.kr/2011/02/how-containerof-macro-works-example.html
Решил попробовать для своих целей, но не могу понять почему оно не работает в моем случаи и хотелось бы понять, как оно вообще в целом работает. Подскажите пожайлуста:
Код

#include <stdio.h>
#include <stdlib.h>

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) ({            \
 const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
 (type *)( (char *)__mptr - offsetof(type,member) );})

struct vma_area {
    struct mm_struct *mm;
};

struct mm_struct { // test1
     struct vma_area *vma;
};

struct task_struct { // test2
     int pid;
     struct mm_struct *mm;
};

int main()
{
    struct task_struct *ts = malloc(sizeof(struct task_struct));
    if (ts == NULL) {
        return 1;
    }

    ts->pid         =   1245;
    ts->mm          =   malloc(sizeof(struct mm_struct));
    ts->mm->vma     =   malloc(sizeof(struct vma_area));
    ts->mm->vma->mm =   ts->mm;

//    struct vma_area *my_vma = ts->mm->vma;

    struct mm_struct *my_mm = &ts->mm; /*&my_vma->mm;*/

    struct task_struct *new_ts = container_of(my_mm, struct task_struct, mm);

    printf("pid = %d\n", new_ts->pid);

 return EXIT_SUCCESS;
}


Собственно если я расскоментирую вот эту часть *&my_vma->mm;*/, то я уже pid получу не верный, почему? И почему если я вместо  struct mm_struct *my_mm = &ts->mm;  напишу  struct mm_struct *my_mm = ts->mm; , то нефига опять работать не будет, там ведт вроде не должно быть - & ?

Автор: mes 16.8.2013, 09:33
проблема в указателе, вам нужен адрес поля mm (т.е. указатель на указатель), а не того обьекта, на который это поле указывает..

Автор: newbie2009 16.8.2013, 10:30
Спасибо, в этом я разобрался + вы подвердили.

Я не множко переписал тестовое приложение:
Код

#include <stdio.h>
#include <stdlib.h>

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) ({            \
 const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
 (type *)( (char *)__mptr - offsetof(type,member) );})

struct vma_area {
    struct mm_struct *mm;
};

struct mm_struct { // test1
    struct vma_area *vma;
};

struct task_struct { // test2
     int pid;
     struct mm_struct *mm;
};

int main()
{
    struct task_struct *TS = malloc(sizeof(struct task_struct));
    if (TS == NULL) {
        return 1;
    }

    TS->pid = 1245;

    struct vma_area *VMA = malloc(sizeof(struct vma_area));
    struct mm_struct *MM = malloc(sizeof(struct mm_struct));

    TS->mm = MM;
    VMA->mm = MM;
    MM->vma = VMA;
    //------------------------------------------------------------------------------------------------------------
    struct task_struct *my_ts = container_of(&VMA->mm, struct task_struct, mm);
    if (my_ts == TS) {
        printf("TSs is equal\n");
    }

    return EXIT_SUCCESS;
}


Я так понимаю в этом случаи я не смогу получить используя VMA->mm структурку task_struct? Или я опять не правильно использую макрос? Исходя из того, как этот макрос работает я так понял у меня не выйдет сделать. Или я не прав?

Автор: xvr 16.8.2013, 11:51
Цитата(newbie2009 @  16.8.2013,  10:30 Найти цитируемый пост)
Я так понимаю в этом случаи я не смогу получить используя VMA->mm структурку task_struct?

Не сможете

Цитата(newbie2009 @  16.8.2013,  10:30 Найти цитируемый пост)
Исходя из того, как этот макрос работает я так понял у меня не выйдет сделать.

Угу, это принципиально невозможно. container_of позволяет перемещаться внутри структуры, имея адрес какого то ее поля. Но он никоим образом не может перескачить из одной структуры в совершенно другую, даже если в них есть поля с одинаковым содержимым (это ваш MM)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)