2011-04-05 9 views
23
user/include/linux/list.h 

esta declaración:list_entry en Linux

#define list_entry(ptr, type, member) \ 
((type *)((char *)(ptr) – (unsigned long)(&((type *)0)->member))) 

puede alguien explicar qué es esto y cómo funciona, gracias por adelantado

P. S. por favor, simplifique su respuesta lo más posible, conozco los hilos, los procesos en Linux, ahora estoy explorando posibilidades y estoy un poco atrapado con esta.

+0

Hoy en día [list_entry] (http://lxr.free-electrons.com/ident?i=list_entry) macro [se define] (http : //lxr.free-electrons.com/source/include/linux/list.h) como [container_of] (http://lxr.free-electrons.com/ident?i=container_of) macro (que es casi idéntica) a la antigua versión de 'list_entry' que publicaste) que fue explicada en gran medida por [Radek Pazdera] (https://github.com/pazdera) en [su blog] (http://radek.io/2012/11/10/ mágico-contenedor_de-macro /). Hasta donde sé, este cambio se realizó entre la versión del núcleo [2.4.37] (http://lxr.free-electrons.com/source/include/linux/list.h?v=2.4.37) y '2.6. 11'. –

Respuesta

27

considerar dos estructuras de este tipo:

struct data { 
    int something; 
}; 

struct container { 
    int something_before; 
    struct data data_item; 
    int something_after; 
}; 

Suponga que tiene un puntero a un valor struct data:

struct data *data_ptr; 

La macro list_entry() le ayuda para convertir data_ptr en un puntero al valor struct container que contiene el struct data valor, a la que apunta ptr:

struct container *cont_ptr = list_entry(data_ptr, struct container, data_item); 

Los macro funciona mediante el cálculo de la compensación de data_item dentro del struct container, y restando esa cantidad de bytes desde el puntero data_ptr. Esto, cuando se envía a struct container *, da un puntero válido al struct container que contiene este particular struct data "dentro".

La macro también se puede simplificar un poco mediante el uso de la orden interna offsetof() macro:

#define list_entry(ptr, type, member) \ 
    ((type *)((char *)(ptr) – offsetof(type, member))) 
+0

Excelente explicación! – kumar

+0

La compilación da error en "-" (en guión). Cambie en guión a "-" (signo menos). – Jossi

2

Esta macro se utiliza para encontrar la dirección de una estructura dada uno de sus miembros.

Así, por ejemplo, suponga que tiene la estructura:

typedef struct 
{ 
    int i; 
    int j; 
} typestruct; 

Lo primero que debe saber es que la última parte de la macro:

&((typestruct *)0)->j 

se utiliza para dar el offset de un miembro. Por lo tanto, es el tamaño, en bytes, de zero memoria que se aplica al tipo, al miembro. En este caso, es el sizeof(int), porque j es justo debajo de int i; Asumamos que esta expresión vale 4 por simplicidad. Se puede obtener el mismo resultado con la macro

offsetof(typestruct, j); 

Ahora queremos calcular la dirección de temp, donde temp es typestruct temp. Para hacer eso, calculamos simplemente la dirección del puntero menos la posición del miembro.La dirección del puntero es:

(typestruct *)((char *) &temp.j) 

Por lo tanto, la resta es:

&temp == (typestruct *)((char *) &temp.j) - offsetof(typestruct, j) 

o, como en la macro dice:

&temp == (typestruct *)((char *) &temp.j) - &((typestruct *)0)->j 

Usted puede aprender mucho más here, y también en este question.

(paréntesis son necesarios, pero fue eliminada de aclaración)